From 2a77938342ef9384305c3172801b320eddbdd7a3 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 15:11:18 +0100 Subject: [PATCH 01/17] Move Array2d to Lists Signed-off-by: Kamil Tekiela --- src/Components/{ => Lists}/Array2d.php | 17 +++-------------- src/Parser.php | 4 ++-- src/Statements/InsertStatement.php | 2 +- src/Statements/ReplaceStatement.php | 2 +- src/Statements/WithStatement.php | 2 +- tests/Components/Array2dTest.php | 2 +- 6 files changed, 9 insertions(+), 20 deletions(-) rename src/Components/{ => Lists}/Array2d.php (89%) diff --git a/src/Components/Array2d.php b/src/Components/Lists/Array2d.php similarity index 89% rename from src/Components/Array2d.php rename to src/Components/Lists/Array2d.php index f73e267e..57421e03 100644 --- a/src/Components/Array2d.php +++ b/src/Components/Lists/Array2d.php @@ -2,15 +2,14 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components; +namespace PhpMyAdmin\SqlParser\Components\Lists; -use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; use PhpMyAdmin\SqlParser\Translator; -use RuntimeException; use function count; use function sprintf; @@ -18,7 +17,7 @@ /** * `VALUES` keyword parser. */ -final class Array2d implements Component +final class Array2d { /** * @param Parser $parser the parser that serves as context @@ -109,14 +108,4 @@ public static function parse(Parser $parser, TokensList $list, array $options = return $ret; } - - public function build(): string - { - throw new RuntimeException(Translator::gettext('Not implemented yet.')); - } - - public function __toString(): string - { - return $this->build(); - } } diff --git a/src/Parser.php b/src/Parser.php index a95816e9..7e3712c1 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -334,11 +334,11 @@ class Parser 'field' => 'index_hints', ], 'VALUE' => [ - 'class' => Components\Array2d::class, + 'class' => Components\Lists\Array2d::class, 'field' => 'values', ], 'VALUES' => [ - 'class' => Components\Array2d::class, + 'class' => Components\Lists\Array2d::class, 'field' => 'values', ], 'WHERE' => [ diff --git a/src/Statements/InsertStatement.php b/src/Statements/InsertStatement.php index 99818bc5..5bcb51b3 100644 --- a/src/Statements/InsertStatement.php +++ b/src/Statements/InsertStatement.php @@ -4,9 +4,9 @@ namespace PhpMyAdmin\SqlParser\Statements; -use PhpMyAdmin\SqlParser\Components\Array2d; use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Components\IntoKeyword; +use PhpMyAdmin\SqlParser\Components\Lists\Array2d; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\SetOperation; use PhpMyAdmin\SqlParser\Parser; diff --git a/src/Statements/ReplaceStatement.php b/src/Statements/ReplaceStatement.php index c3a74b1e..cad7515c 100644 --- a/src/Statements/ReplaceStatement.php +++ b/src/Statements/ReplaceStatement.php @@ -4,9 +4,9 @@ namespace PhpMyAdmin\SqlParser\Statements; -use PhpMyAdmin\SqlParser\Components\Array2d; use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Components\IntoKeyword; +use PhpMyAdmin\SqlParser\Components\Lists\Array2d; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\SetOperation; use PhpMyAdmin\SqlParser\Parser; diff --git a/src/Statements/WithStatement.php b/src/Statements/WithStatement.php index 307e371d..242e4c53 100644 --- a/src/Statements/WithStatement.php +++ b/src/Statements/WithStatement.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Statements; -use PhpMyAdmin\SqlParser\Components\Array2d; +use PhpMyAdmin\SqlParser\Components\Lists\Array2d; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\WithKeyword; use PhpMyAdmin\SqlParser\Exceptions\ParserException; diff --git a/tests/Components/Array2dTest.php b/tests/Components/Array2dTest.php index fe875807..a44e037c 100644 --- a/tests/Components/Array2dTest.php +++ b/tests/Components/Array2dTest.php @@ -4,8 +4,8 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\Array2d; use PhpMyAdmin\SqlParser\Components\ArrayObj; +use PhpMyAdmin\SqlParser\Components\Lists\Array2d; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Tests\TestCase; From 566472d16c0a3fbcfae6572b8cfa5d2dd47fcb0d Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 15:43:39 +0100 Subject: [PATCH 02/17] Remove contract for parse method Signed-off-by: Kamil Tekiela --- psalm-baseline.xml | 52 ++++++++++++++++++++++++++++++---- src/Component.php | 9 ------ src/Components/WithKeyword.php | 16 ----------- 3 files changed, 47 insertions(+), 30 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 1c158853..4a80fcbe 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -19,11 +19,6 @@ field)]]> - - - $state === 1 - - $ret[] @@ -82,6 +77,9 @@ alias)]]> alias)]]> + + $options + @@ -99,6 +97,9 @@ $state === 5 + + $options + @@ -112,6 +113,9 @@ $state === 1 + + $options + @@ -175,6 +179,9 @@ $state === 1 + + $options + @@ -191,6 +198,9 @@ expr)]]> expr)]]> + + $options + @@ -250,6 +260,9 @@ keyword])]]> keyword])]]> + + $options + @@ -274,6 +287,9 @@ $state === 5 + + $options + @@ -281,6 +297,11 @@ rowCount]]> + + + $state === 1 + + $table @@ -289,6 +310,9 @@ 'table'])]]> + + $options + @@ -388,6 +412,9 @@ expr)]]> expr)]]> + + $options + @@ -405,6 +432,9 @@ name)]]> + + $options + @@ -445,6 +475,9 @@ options)]]> + + $options + $idx @@ -468,6 +501,9 @@ $state === 2 + + $options + @@ -496,6 +532,9 @@ old)]]> + + $options + @@ -505,6 +544,9 @@ $state === 1 value === ',']]> + + $options + diff --git a/src/Component.php b/src/Component.php index d1c44567..65b600a9 100644 --- a/src/Component.php +++ b/src/Component.php @@ -16,15 +16,6 @@ */ interface Component extends Stringable { - /** - * Parses the tokens contained in the given list in the context of the given parser. - * - * @param Parser $parser the parser that serves as context - * @param TokensList $list the list of tokens that are being parsed - * @param array $options parameters for parsing - */ - public static function parse(Parser $parser, TokensList $list, array $options = []): mixed; - /** * Builds the string representation of a component of this type. * diff --git a/src/Components/WithKeyword.php b/src/Components/WithKeyword.php index c98924b6..a228f91b 100644 --- a/src/Components/WithKeyword.php +++ b/src/Components/WithKeyword.php @@ -6,8 +6,6 @@ use PhpMyAdmin\SqlParser\Component; use PhpMyAdmin\SqlParser\Parser; -use PhpMyAdmin\SqlParser\TokensList; -use PhpMyAdmin\SqlParser\Translator; use RuntimeException; /** @@ -29,20 +27,6 @@ public function __construct(string $name) $this->name = $name; } - /** - * Parses the tokens contained in the given list in the context of the given parser. - * - * @param Parser $parser the parser that serves as context - * @param TokensList $list the list of tokens that are being parsed - * @param array $options parameters for parsing - * - * @throws RuntimeException not implemented yet. - */ - public static function parse(Parser $parser, TokensList $list, array $options = []): mixed - { - throw new RuntimeException(Translator::gettext('Not implemented yet.')); - } - public function build(): string { if (! isset($this->statement)) { From 75b2e290d15dc478e423ff6c0d0464f607f8dc09 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 15:25:39 +0100 Subject: [PATCH 03/17] Split up Condition class Signed-off-by: Kamil Tekiela c --- psalm-baseline.xml | 18 --- src/Components/CaseExpression.php | 5 +- src/Components/Condition.php | 180 -------------------------- src/Components/JoinKeyword.php | 5 +- src/Components/Lists/Conditions.php | 192 ++++++++++++++++++++++++++++ src/Parser.php | 4 +- src/Statements/DeleteStatement.php | 7 +- tests/Components/ConditionTest.php | 6 +- 8 files changed, 207 insertions(+), 210 deletions(-) create mode 100644 src/Components/Lists/Conditions.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 4a80fcbe..8ff1b0ef 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -113,9 +113,6 @@ $state === 1 - - $options - @@ -179,9 +176,6 @@ $state === 1 - - $options - @@ -287,9 +281,6 @@ $state === 5 - - $options - @@ -310,9 +301,6 @@ 'table'])]]> - - $options - @@ -475,9 +463,6 @@ options)]]> - - $options - $idx @@ -501,9 +486,6 @@ $state === 2 - - $options - diff --git a/src/Components/CaseExpression.php b/src/Components/CaseExpression.php index 68a01a9c..af8633ee 100644 --- a/src/Components/CaseExpression.php +++ b/src/Components/CaseExpression.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Components\Lists\Conditions; use PhpMyAdmin\SqlParser\Context; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; @@ -104,7 +105,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = switch ($token->keyword) { case 'WHEN': ++$list->idx; // Skip 'WHEN' - $newCondition = Condition::parse($parser, $list); + $newCondition = Conditions::parse($parser, $list); $type = 1; $state = 1; $ret->conditions[] = $newCondition; @@ -264,7 +265,7 @@ public function build(): string $valuesCount = count($this->conditions); $resultsCount = count($this->results); for ($i = 0; $i < $valuesCount && $i < $resultsCount; ++$i) { - $ret .= 'WHEN ' . Condition::buildAll($this->conditions[$i]) . ' '; + $ret .= 'WHEN ' . Conditions::buildAll($this->conditions[$i]) . ' '; $ret .= 'THEN ' . $this->results[$i] . ' '; } } diff --git a/src/Components/Condition.php b/src/Components/Condition.php index c3ef05cc..d24a58a8 100644 --- a/src/Components/Condition.php +++ b/src/Components/Condition.php @@ -5,57 +5,11 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; -use PhpMyAdmin\SqlParser\Parser; -use PhpMyAdmin\SqlParser\Token; -use PhpMyAdmin\SqlParser\TokensList; -use PhpMyAdmin\SqlParser\TokenType; -use function implode; -use function in_array; use function trim; -/** - * `WHERE` keyword parser. - */ final class Condition implements Component { - /** - * Logical operators that can be used to delimit expressions. - */ - private const DELIMITERS = [ - '&&', - '||', - 'AND', - 'OR', - 'XOR', - ]; - - /** - * List of allowed reserved keywords in conditions. - */ - private const ALLOWED_KEYWORDS = [ - 'ALL', - 'AND', - 'BETWEEN', - 'COLLATE', - 'EXISTS', - 'IF', - 'IN', - 'INTERVAL', - 'IS', - 'LIKE', - 'MATCH', - 'NOT IN', - 'NOT NULL', - 'NOT', - 'NULL', - 'OR', - 'REGEXP', - 'RLIKE', - 'SOUNDS', - 'XOR', - ]; - /** * Identifiers recognized. * @@ -83,145 +37,11 @@ public function __construct(string|null $expr = null) $this->expr = trim((string) $expr); } - /** - * @param Parser $parser the parser that serves as context - * @param TokensList $list the list of tokens that are being parsed - * @param array $options parameters for parsing - * - * @return Condition[] - */ - public static function parse(Parser $parser, TokensList $list, array $options = []): array - { - $ret = []; - - $expr = new static(); - - /** - * Counts brackets. - */ - $brackets = 0; - - /** - * Whether there was a `BETWEEN` keyword before or not. - * - * It is required to keep track of them because their structure contains - * the keyword `AND`, which is also an operator that delimits - * expressions. - */ - $betweenBefore = false; - - for (; $list->idx < $list->count; ++$list->idx) { - /** - * Token parsed at this moment. - */ - $token = $list->tokens[$list->idx]; - - // End of statement. - if ($token->type === TokenType::Delimiter) { - break; - } - - // Skipping whitespaces and comments. - if ($token->type === TokenType::Comment) { - continue; - } - - // Replacing all whitespaces (new lines, tabs, etc.) with a single - // space character. - if ($token->type === TokenType::Whitespace) { - $expr->expr .= ' '; - continue; - } - - // Conditions are delimited by logical operators. - if (in_array($token->value, self::DELIMITERS, true)) { - if ($betweenBefore && ($token->value === 'AND')) { - // The syntax of keyword `BETWEEN` is hard-coded. - $betweenBefore = false; - } else { - // The expression ended. - $expr->expr = trim($expr->expr); - if (! empty($expr->expr)) { - $ret[] = $expr; - } - - // Adding the operator. - $expr = new static($token->value); - $expr->isOperator = true; - $ret[] = $expr; - - // Preparing to parse another condition. - $expr = new static(); - continue; - } - } - - if ( - ($token->type === TokenType::Keyword) - && ($token->flags & Token::FLAG_KEYWORD_RESERVED) - && ! ($token->flags & Token::FLAG_KEYWORD_FUNCTION) - ) { - if ($token->value === 'BETWEEN') { - $betweenBefore = true; - } - - if ($brackets === 0 && ! in_array($token->value, self::ALLOWED_KEYWORDS, true)) { - break; - } - } - - if ($token->type === TokenType::Operator) { - if ($token->value === '(') { - ++$brackets; - } elseif ($token->value === ')') { - if ($brackets === 0) { - break; - } - - --$brackets; - } - } - - $expr->expr .= $token->token; - if ( - ($token->type !== TokenType::None) - && (($token->type !== TokenType::Keyword) - || ($token->flags & Token::FLAG_KEYWORD_RESERVED)) - && ($token->type !== TokenType::String) - && ($token->type !== TokenType::Symbol || ($token->flags & Token::FLAG_SYMBOL_PARAMETER)) - ) { - continue; - } - - if (in_array($token->value, $expr->identifiers)) { - continue; - } - - $expr->identifiers[] = $token->value; - } - - // Last iteration was not processed. - $expr->expr = trim($expr->expr); - if (! empty($expr->expr)) { - $ret[] = $expr; - } - - --$list->idx; - - return $ret; - } - public function build(): string { return $this->expr; } - /** @param Condition[] $component the component to be built */ - public static function buildAll(array $component): string - { - return implode(' ', $component); - } - public function __toString(): string { return $this->build(); diff --git a/src/Components/JoinKeyword.php b/src/Components/JoinKeyword.php index cf87998c..6ee26e56 100644 --- a/src/Components/JoinKeyword.php +++ b/src/Components/JoinKeyword.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Components\Lists\Conditions; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -178,7 +179,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = } } } elseif ($state === 3) { - $expr->on = Condition::parse($parser, $list); + $expr->on = Conditions::parse($parser, $list); $ret[] = $expr; $expr = new static(); $state = 0; @@ -211,7 +212,7 @@ public static function buildAll(array $component): string foreach ($component as $c) { $ret[] = array_search($c->type, self::JOINS) . ' ' . $c->expr . (! empty($c->on) - ? ' ON ' . Condition::buildAll($c->on) : '') + ? ' ON ' . Conditions::buildAll($c->on) : '') . (! empty($c->using) ? ' USING ' . $c->using->build() : ''); } diff --git a/src/Components/Lists/Conditions.php b/src/Components/Lists/Conditions.php new file mode 100644 index 00000000..bcea33d0 --- /dev/null +++ b/src/Components/Lists/Conditions.php @@ -0,0 +1,192 @@ + $options parameters for parsing + * + * @return Condition[] + */ + public static function parse(Parser $parser, TokensList $list, array $options = []): array + { + $ret = []; + + $expr = new Condition(); + + /** + * Counts brackets. + */ + $brackets = 0; + + /** + * Whether there was a `BETWEEN` keyword before or not. + * + * It is required to keep track of them because their structure contains + * the keyword `AND`, which is also an operator that delimits + * expressions. + */ + $betweenBefore = false; + + for (; $list->idx < $list->count; ++$list->idx) { + /** + * Token parsed at this moment. + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === TokenType::Delimiter) { + break; + } + + // Skipping whitespaces and comments. + if ($token->type === TokenType::Comment) { + continue; + } + + // Replacing all whitespaces (new lines, tabs, etc.) with a single + // space character. + if ($token->type === TokenType::Whitespace) { + $expr->expr .= ' '; + continue; + } + + // Conditions are delimited by logical operators. + if (in_array($token->value, self::DELIMITERS, true)) { + if ($betweenBefore && ($token->value === 'AND')) { + // The syntax of keyword `BETWEEN` is hard-coded. + $betweenBefore = false; + } else { + // The expression ended. + $expr->expr = trim($expr->expr); + if (! empty($expr->expr)) { + $ret[] = $expr; + } + + // Adding the operator. + $expr = new Condition($token->value); + $expr->isOperator = true; + $ret[] = $expr; + + // Preparing to parse another condition. + $expr = new Condition(); + continue; + } + } + + if ( + ($token->type === TokenType::Keyword) + && ($token->flags & Token::FLAG_KEYWORD_RESERVED) + && ! ($token->flags & Token::FLAG_KEYWORD_FUNCTION) + ) { + if ($token->value === 'BETWEEN') { + $betweenBefore = true; + } + + if ($brackets === 0 && ! in_array($token->value, self::ALLOWED_KEYWORDS, true)) { + break; + } + } + + if ($token->type === TokenType::Operator) { + if ($token->value === '(') { + ++$brackets; + } elseif ($token->value === ')') { + if ($brackets === 0) { + break; + } + + --$brackets; + } + } + + $expr->expr .= $token->token; + if ( + ($token->type !== TokenType::None) + && (($token->type !== TokenType::Keyword) + || ($token->flags & Token::FLAG_KEYWORD_RESERVED)) + && ($token->type !== TokenType::String) + && ($token->type !== TokenType::Symbol || ($token->flags & Token::FLAG_SYMBOL_PARAMETER)) + ) { + continue; + } + + if (in_array($token->value, $expr->identifiers)) { + continue; + } + + $expr->identifiers[] = $token->value; + } + + // Last iteration was not processed. + $expr->expr = trim($expr->expr); + if (! empty($expr->expr)) { + $ret[] = $expr; + } + + --$list->idx; + + return $ret; + } + + /** @param Condition[] $component the component to be built */ + public static function buildAll(array $component): string + { + return implode(' ', $component); + } +} diff --git a/src/Parser.php b/src/Parser.php index 7e3712c1..1fbd2a8e 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -204,7 +204,7 @@ class Parser 'field' => 'group', ], 'HAVING' => [ - 'class' => Components\Condition::class, + 'class' => Components\Lists\Conditions::class, 'field' => 'having', ], 'IGNORE' => [ @@ -342,7 +342,7 @@ class Parser 'field' => 'values', ], 'WHERE' => [ - 'class' => Components\Condition::class, + 'class' => Components\Lists\Conditions::class, 'field' => 'where', ], ]; diff --git a/src/Statements/DeleteStatement.php b/src/Statements/DeleteStatement.php index dee3bd79..8630b27b 100644 --- a/src/Statements/DeleteStatement.php +++ b/src/Statements/DeleteStatement.php @@ -10,6 +10,7 @@ use PhpMyAdmin\SqlParser\Components\ExpressionArray; use PhpMyAdmin\SqlParser\Components\JoinKeyword; use PhpMyAdmin\SqlParser\Components\Limit; +use PhpMyAdmin\SqlParser\Components\Lists\Conditions; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\OrderKeyword; use PhpMyAdmin\SqlParser\Parser; @@ -173,7 +174,7 @@ public function build(): string } if ($this->where !== null && $this->where !== []) { - $ret .= ' WHERE ' . Condition::buildAll($this->where); + $ret .= ' WHERE ' . Conditions::buildAll($this->where); } if ($this->order !== null && $this->order !== []) { @@ -278,7 +279,7 @@ public function parse(Parser $parser, TokensList $list): void break; case 'WHERE': ++$list->idx; // Skip 'WHERE' - $this->where = Condition::parse($parser, $list); + $this->where = Conditions::parse($parser, $list); $state = 4; break; case 'ORDER BY': @@ -309,7 +310,7 @@ public function parse(Parser $parser, TokensList $list): void } ++$list->idx; // Skip 'WHERE' - $this->where = Condition::parse($parser, $list); + $this->where = Conditions::parse($parser, $list); $state = 4; } elseif ($state === 4) { if ($multiTable === true && $token->type === TokenType::Keyword) { diff --git a/tests/Components/ConditionTest.php b/tests/Components/ConditionTest.php index ae417df2..d40c8a5e 100644 --- a/tests/Components/ConditionTest.php +++ b/tests/Components/ConditionTest.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\Condition; +use PhpMyAdmin\SqlParser\Components\Lists\Conditions; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Tests\TestCase; @@ -12,13 +12,13 @@ class ConditionTest extends TestCase { public function testParse(): void { - $component = Condition::parse(new Parser(), $this->getTokensList('/* id = */ id = 10')); + $component = Conditions::parse(new Parser(), $this->getTokensList('/* id = */ id = 10')); $this->assertEquals($component[0]->expr, 'id = 10'); } public function testParseBetween(): void { - $component = Condition::parse( + $component = Conditions::parse( new Parser(), $this->getTokensList('(id BETWEEN 10 AND 20) OR (id BETWEEN 30 AND 40)'), ); From 7741cfd82d21c40385806127aa48a49560180b2d Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 15:45:44 +0100 Subject: [PATCH 04/17] Split up CreateDefinition Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 10 +- psalm-baseline.xml | 16 +- src/Components/CreateDefinition.php | 231 ------------------- src/Components/Lists/CreateDefinitions.php | 251 +++++++++++++++++++++ src/Statements/CreateStatement.php | 5 +- tests/Builder/CreateStatementTest.php | 5 +- tests/Components/CreateDefinitionTest.php | 10 +- 7 files changed, 273 insertions(+), 255 deletions(-) create mode 100644 src/Components/Lists/CreateDefinitions.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c21b19e8..ba5e7511 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -45,11 +45,6 @@ parameters: count: 2 path: src/Components/CaseExpression.php - - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\CreateDefinition\\:\\:\\$name \\(string\\|null\\) does not accept mixed\\.$#" - count: 2 - path: src/Components/CreateDefinition.php - - message: "#^Cannot access property \\$raw on array\\\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\.$#" count: 1 @@ -210,6 +205,11 @@ parameters: count: 1 path: src/Components/Limit.php + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\CreateDefinition\\:\\:\\$name \\(string\\|null\\) does not accept mixed\\.$#" + count: 2 + path: src/Components/Lists/CreateDefinitions.php + - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\LockExpression\\:\\:\\$table \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 8ff1b0ef..f9b5edb1 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -87,19 +87,9 @@ - - name]]> - name]]> - options]]> - - $state === 5 - - - $options - @@ -293,6 +283,12 @@ $state === 1 + + + name]]> + name]]> + + $table diff --git a/src/Components/CreateDefinition.php b/src/Components/CreateDefinition.php index 7dfcdfe3..e07c1003 100644 --- a/src/Components/CreateDefinition.php +++ b/src/Components/CreateDefinition.php @@ -6,12 +6,7 @@ use PhpMyAdmin\SqlParser\Component; use PhpMyAdmin\SqlParser\Context; -use PhpMyAdmin\SqlParser\Parser; -use PhpMyAdmin\SqlParser\Token; -use PhpMyAdmin\SqlParser\TokensList; -use PhpMyAdmin\SqlParser\TokenType; -use function implode; use function trim; /** @@ -21,85 +16,6 @@ */ final class CreateDefinition implements Component { - /** - * All field options. - */ - private const FIELD_OPTIONS = [ - // Tells the `OptionsArray` to not sort the options. - // See the note below. - '_UNSORTED' => true, - - 'NOT NULL' => 1, - 'NULL' => 1, - 'DEFAULT' => [ - 2, - 'expr', - ['breakOnAlias' => true], - ], - /* Following are not according to grammar, but MySQL happily accepts - * these at any location */ - 'CHARSET' => [ - 2, - 'var', - ], - 'COLLATE' => [ - 3, - 'var', - ], - 'AUTO_INCREMENT' => 3, - 'KEY' => 4, - 'PRIMARY' => 4, - 'PRIMARY KEY' => 4, - 'UNIQUE' => 4, - 'UNIQUE KEY' => 4, - 'COMMENT' => [ - 5, - 'var', - ], - 'COLUMN_FORMAT' => [ - 6, - 'var', - ], - 'ON UPDATE' => [ - 7, - 'expr', - ], - - // Generated columns options. - 'GENERATED ALWAYS' => 8, - 'AS' => [ - 9, - 'expr', - ['parenthesesDelimited' => true], - ], - 'VIRTUAL' => 10, - 'PERSISTENT' => 11, - 'STORED' => 11, - 'CHECK' => [ - 12, - 'expr', - ['parenthesesDelimited' => true], - ], - 'INVISIBLE' => 13, - 'ENFORCED' => 14, - 'NOT' => 15, - 'COMPRESSED' => 16, - // Common entries. - // - // NOTE: Some of the common options are not in the same order which - // causes troubles when checking if the options are in the right order. - // I should find a way to define multiple sets of options and make the - // parser select the right set. - // - // 'UNIQUE' => 4, - // 'UNIQUE KEY' => 4, - // 'COMMENT' => [5, 'var'], - // 'NOT NULL' => 1, - // 'NULL' => 1, - // 'PRIMARY' => 4, - // 'PRIMARY KEY' => 4, - ]; - /** * The name of the new column. * @@ -167,147 +83,6 @@ public function __construct( } } - /** - * @param Parser $parser the parser that serves as context - * @param TokensList $list the list of tokens that are being parsed - * @param array $options parameters for parsing - * - * @return CreateDefinition[] - */ - public static function parse(Parser $parser, TokensList $list, array $options = []): array - { - $ret = []; - - $expr = new static(); - - /** - * The state of the parser. - * - * Below are the states of the parser. - * - * 0 -----------------------[ ( ]------------------------> 1 - * - * 1 --------------------[ CONSTRAINT ]------------------> 1 - * 1 -----------------------[ key ]----------------------> 2 - * 1 -------------[ constraint / column name ]-----------> 2 - * - * 2 --------------------[ data type ]-------------------> 3 - * - * 3 ---------------------[ options ]--------------------> 4 - * - * 4 --------------------[ REFERENCES ]------------------> 4 - * - * 5 ------------------------[ , ]-----------------------> 1 - * 5 ------------------------[ ) ]-----------------------> 6 (-1) - */ - $state = 0; - - for (; $list->idx < $list->count; ++$list->idx) { - /** - * Token parsed at this moment. - */ - $token = $list->tokens[$list->idx]; - - // End of statement. - if ($token->type === TokenType::Delimiter) { - break; - } - - // Skipping whitespaces and comments. - if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { - continue; - } - - if ($state === 0) { - if (($token->type !== TokenType::Operator) || ($token->value !== '(')) { - $parser->error('An opening bracket was expected.', $token); - - break; - } - - $state = 1; - } elseif ($state === 1) { - if ($token->type === TokenType::Keyword && $token->keyword === 'CONSTRAINT') { - $expr->isConstraint = true; - } elseif (($token->type === TokenType::Keyword) && ($token->flags & Token::FLAG_KEYWORD_KEY)) { - $expr->key = Key::parse($parser, $list); - $state = 4; - } elseif ($token->type === TokenType::Symbol || $token->type === TokenType::None) { - $expr->name = $token->value; - if (! $expr->isConstraint) { - $state = 2; - } - } elseif ($token->type === TokenType::Keyword) { - if ($token->flags & Token::FLAG_KEYWORD_RESERVED) { - // Reserved keywords can't be used - // as field names without backquotes - $parser->error( - 'A symbol name was expected! ' - . 'A reserved keyword can not be used ' - . 'as a column name without backquotes.', - $token, - ); - - return $ret; - } - - // Non-reserved keywords are allowed without backquotes - $expr->name = $token->value; - $state = 2; - } else { - $parser->error('A symbol name was expected!', $token); - - return $ret; - } - } elseif ($state === 2) { - $expr->type = DataType::parse($parser, $list); - $state = 3; - } elseif ($state === 3) { - $expr->options = OptionsArray::parse($parser, $list, self::FIELD_OPTIONS); - $state = 4; - } elseif ($state === 4) { - if ($token->type === TokenType::Keyword && $token->keyword === 'REFERENCES') { - ++$list->idx; // Skipping keyword 'REFERENCES'. - $expr->references = Reference::parse($parser, $list); - } else { - --$list->idx; - } - - $state = 5; - } elseif ($state === 5) { - if (! empty($expr->type) || ! empty($expr->key)) { - $ret[] = $expr; - } - - $expr = new static(); - if ($token->value === ',') { - $state = 1; - } elseif ($token->value === ')') { - $state = 6; - ++$list->idx; - break; - } else { - $parser->error('A comma or a closing bracket was expected.', $token); - $state = 0; - break; - } - } - } - - // Last iteration was not saved. - if (! empty($expr->type) || ! empty($expr->key)) { - $ret[] = $expr; - } - - if (($state !== 0) && ($state !== 6)) { - $parser->error('A closing bracket was expected.', $list->tokens[$list->idx - 1]); - } - - --$list->idx; - - return $ret; - } - public function build(): string { $tmp = ''; @@ -338,12 +113,6 @@ public function build(): string return trim($tmp); } - /** @param CreateDefinition[] $component the component to be built */ - public static function buildAll(array $component): string - { - return "(\n " . implode(",\n ", $component) . "\n)"; - } - public function __toString(): string { return $this->build(); diff --git a/src/Components/Lists/CreateDefinitions.php b/src/Components/Lists/CreateDefinitions.php new file mode 100644 index 00000000..a3c90ac7 --- /dev/null +++ b/src/Components/Lists/CreateDefinitions.php @@ -0,0 +1,251 @@ + true, + + 'NOT NULL' => 1, + 'NULL' => 1, + 'DEFAULT' => [ + 2, + 'expr', + ['breakOnAlias' => true], + ], + /* Following are not according to grammar, but MySQL happily accepts + * these at any location */ + 'CHARSET' => [ + 2, + 'var', + ], + 'COLLATE' => [ + 3, + 'var', + ], + 'AUTO_INCREMENT' => 3, + 'KEY' => 4, + 'PRIMARY' => 4, + 'PRIMARY KEY' => 4, + 'UNIQUE' => 4, + 'UNIQUE KEY' => 4, + 'COMMENT' => [ + 5, + 'var', + ], + 'COLUMN_FORMAT' => [ + 6, + 'var', + ], + 'ON UPDATE' => [ + 7, + 'expr', + ], + + // Generated columns options. + 'GENERATED ALWAYS' => 8, + 'AS' => [ + 9, + 'expr', + ['parenthesesDelimited' => true], + ], + 'VIRTUAL' => 10, + 'PERSISTENT' => 11, + 'STORED' => 11, + 'CHECK' => [ + 12, + 'expr', + ['parenthesesDelimited' => true], + ], + 'INVISIBLE' => 13, + 'ENFORCED' => 14, + 'NOT' => 15, + 'COMPRESSED' => 16, + // Common entries. + // + // NOTE: Some of the common options are not in the same order which + // causes troubles when checking if the options are in the right order. + // I should find a way to define multiple sets of options and make the + // parser select the right set. + // + // 'UNIQUE' => 4, + // 'UNIQUE KEY' => 4, + // 'COMMENT' => [5, 'var'], + // 'NOT NULL' => 1, + // 'NULL' => 1, + // 'PRIMARY' => 4, + // 'PRIMARY KEY' => 4, + ]; + + /** + * @param Parser $parser the parser that serves as context + * @param TokensList $list the list of tokens that are being parsed + * @param array $options parameters for parsing + * + * @return CreateDefinition[] + */ + public static function parse(Parser $parser, TokensList $list, array $options = []): array + { + $ret = []; + + $expr = new CreateDefinition(); + + /** + * The state of the parser. + * + * Below are the states of the parser. + * + * 0 -----------------------[ ( ]------------------------> 1 + * + * 1 --------------------[ CONSTRAINT ]------------------> 1 + * 1 -----------------------[ key ]----------------------> 2 + * 1 -------------[ constraint / column name ]-----------> 2 + * + * 2 --------------------[ data type ]-------------------> 3 + * + * 3 ---------------------[ options ]--------------------> 4 + * + * 4 --------------------[ REFERENCES ]------------------> 4 + * + * 5 ------------------------[ , ]-----------------------> 1 + * 5 ------------------------[ ) ]-----------------------> 6 (-1) + */ + $state = 0; + + for (; $list->idx < $list->count; ++$list->idx) { + /** + * Token parsed at this moment. + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === TokenType::Delimiter) { + break; + } + + // Skipping whitespaces and comments. + if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { + continue; + } + + if ($state === 0) { + if (($token->type !== TokenType::Operator) || ($token->value !== '(')) { + $parser->error('An opening bracket was expected.', $token); + + break; + } + + $state = 1; + } elseif ($state === 1) { + if ($token->type === TokenType::Keyword && $token->keyword === 'CONSTRAINT') { + $expr->isConstraint = true; + } elseif (($token->type === TokenType::Keyword) && ($token->flags & Token::FLAG_KEYWORD_KEY)) { + $expr->key = Key::parse($parser, $list); + $state = 4; + } elseif ($token->type === TokenType::Symbol || $token->type === TokenType::None) { + $expr->name = $token->value; + if (! $expr->isConstraint) { + $state = 2; + } + } elseif ($token->type === TokenType::Keyword) { + if ($token->flags & Token::FLAG_KEYWORD_RESERVED) { + // Reserved keywords can't be used + // as field names without backquotes + $parser->error( + 'A symbol name was expected! ' + . 'A reserved keyword can not be used ' + . 'as a column name without backquotes.', + $token, + ); + + return $ret; + } + + // Non-reserved keywords are allowed without backquotes + $expr->name = $token->value; + $state = 2; + } else { + $parser->error('A symbol name was expected!', $token); + + return $ret; + } + } elseif ($state === 2) { + $expr->type = DataType::parse($parser, $list); + $state = 3; + } elseif ($state === 3) { + $expr->options = OptionsArray::parse($parser, $list, self::FIELD_OPTIONS); + $state = 4; + } elseif ($state === 4) { + if ($token->type === TokenType::Keyword && $token->keyword === 'REFERENCES') { + ++$list->idx; // Skipping keyword 'REFERENCES'. + $expr->references = Reference::parse($parser, $list); + } else { + --$list->idx; + } + + $state = 5; + } elseif ($state === 5) { + if (! empty($expr->type) || ! empty($expr->key)) { + $ret[] = $expr; + } + + $expr = new CreateDefinition(); + if ($token->value === ',') { + $state = 1; + } elseif ($token->value === ')') { + $state = 6; + ++$list->idx; + break; + } else { + $parser->error('A comma or a closing bracket was expected.', $token); + $state = 0; + break; + } + } + } + + // Last iteration was not saved. + if (! empty($expr->type) || ! empty($expr->key)) { + $ret[] = $expr; + } + + if (($state !== 0) && ($state !== 6)) { + $parser->error('A closing bracket was expected.', $list->tokens[$list->idx - 1]); + } + + --$list->idx; + + return $ret; + } + + /** @param CreateDefinition[] $component the component to be built */ + public static function buildAll(array $component): string + { + return "(\n " . implode(",\n ", $component) . "\n)"; + } +} diff --git a/src/Statements/CreateStatement.php b/src/Statements/CreateStatement.php index 3ecc5524..a99c26c2 100644 --- a/src/Statements/CreateStatement.php +++ b/src/Statements/CreateStatement.php @@ -8,6 +8,7 @@ use PhpMyAdmin\SqlParser\Components\CreateDefinition; use PhpMyAdmin\SqlParser\Components\DataType; use PhpMyAdmin\SqlParser\Components\Expression; +use PhpMyAdmin\SqlParser\Components\Lists\CreateDefinitions; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\ParameterDefinition; use PhpMyAdmin\SqlParser\Components\PartitionDefinition; @@ -380,7 +381,7 @@ public function build(): string $fields = ''; if ($this->fields !== null && $this->fields !== []) { if (is_array($this->fields)) { - $fields = CreateDefinition::buildAll($this->fields) . ' '; + $fields = CreateDefinitions::buildAll($this->fields) . ' '; } else { $fields = $this->fields->build(); } @@ -568,7 +569,7 @@ public function parse(Parser $parser, TokensList $list): void $parser->error('A table name was expected.', $list->tokens[$list->idx]); } } else { - $this->fields = CreateDefinition::parse($parser, $list); + $this->fields = CreateDefinitions::parse($parser, $list); if ($this->fields === []) { $parser->error('At least one column definition was expected.', $list->tokens[$list->idx]); } diff --git a/tests/Builder/CreateStatementTest.php b/tests/Builder/CreateStatementTest.php index d3b40a0c..942c9964 100644 --- a/tests/Builder/CreateStatementTest.php +++ b/tests/Builder/CreateStatementTest.php @@ -8,6 +8,7 @@ use PhpMyAdmin\SqlParser\Components\DataType; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\Key; +use PhpMyAdmin\SqlParser\Components\Lists\CreateDefinitions; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\ParameterDefinition; use PhpMyAdmin\SqlParser\Parser; @@ -754,7 +755,7 @@ public function testBuildCreateTableSortedIndex(): void $this->assertIsArray($stmt->fields); $this->assertEquals( $tableBody, - CreateDefinition::buildAll($stmt->fields), + CreateDefinitions::buildAll($stmt->fields), ); $this->assertEquals( @@ -854,7 +855,7 @@ public function testBuildCreateTableComplexIndexes(): void $this->assertIsArray($stmt->fields); $this->assertEquals( $tableBody, - CreateDefinition::buildAll($stmt->fields), + CreateDefinitions::buildAll($stmt->fields), ); $this->assertEquals( diff --git a/tests/Components/CreateDefinitionTest.php b/tests/Components/CreateDefinitionTest.php index f30f49e5..1cd7e008 100644 --- a/tests/Components/CreateDefinitionTest.php +++ b/tests/Components/CreateDefinitionTest.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\CreateDefinition; +use PhpMyAdmin\SqlParser\Components\Lists\CreateDefinitions; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statements\CreateStatement; use PhpMyAdmin\SqlParser\Tests\TestCase; @@ -13,7 +13,7 @@ class CreateDefinitionTest extends TestCase { public function testParse(): void { - $component = CreateDefinition::parse( + $component = CreateDefinitions::parse( new Parser(), $this->getTokensList('(str TEXT, FULLTEXT INDEX indx (str))'), ); @@ -25,7 +25,7 @@ public function testParse(): void public function testParse2(): void { - $component = CreateDefinition::parse( + $component = CreateDefinitions::parse( new Parser(), $this->getTokensList('(str TEXT NOT NULL INVISIBLE)'), ); @@ -38,7 +38,7 @@ public function testParse2(): void public function testParseErr1(): void { $parser = new Parser(); - $component = CreateDefinition::parse( + $component = CreateDefinitions::parse( $parser, $this->getTokensList('(str TEXT, FULLTEXT INDEX indx (str)'), ); @@ -53,7 +53,7 @@ public function testParseErr1(): void public function testParseErr2(): void { $parser = new Parser(); - CreateDefinition::parse( + CreateDefinitions::parse( $parser, $this->getTokensList(')'), ); From 8f9717a38cacaa55440bd2ba1ed97dd18820e62e Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 15:49:23 +0100 Subject: [PATCH 05/17] Move ExpressionArray to Lists Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 40 +++++++++---------- psalm-baseline.xml | 32 +++++++-------- src/Components/IndexHint.php | 1 + src/Components/IntoKeyword.php | 1 + .../{ => Lists}/ExpressionArray.php | 19 ++------- src/Parser.php | 22 +++++----- src/Statements/DeleteStatement.php | 2 +- src/Statements/LoadStatement.php | 2 +- tests/Components/ExpressionArrayTest.php | 2 +- 9 files changed, 56 insertions(+), 65 deletions(-) rename src/Components/{ => Lists}/ExpressionArray.php (89%) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ba5e7511..aa0bc968 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -85,26 +85,6 @@ parameters: count: 1 path: src/Components/Expression.php - - - message: "#^Method PhpMyAdmin\\\\SqlParser\\\\Components\\\\ExpressionArray\\:\\:parse\\(\\) should return array\\ but returns array\\, PhpMyAdmin\\\\SqlParser\\\\Components\\\\CaseExpression\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\>\\.$#" - count: 1 - path: src/Components/ExpressionArray.php - - - - message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|null given\\.$#" - count: 1 - path: src/Components/ExpressionArray.php - - - - message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|null given\\.$#" - count: 1 - path: src/Components/ExpressionArray.php - - - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#" - count: 1 - path: src/Components/ExpressionArray.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\FunctionCall\\:\\:\\$parameters \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\|null\\) does not accept array\\\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\.$#" count: 1 @@ -210,6 +190,26 @@ parameters: count: 2 path: src/Components/Lists/CreateDefinitions.php + - + message: "#^Method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Lists\\\\ExpressionArray\\:\\:parse\\(\\) should return array\\ but returns array\\, PhpMyAdmin\\\\SqlParser\\\\Components\\\\CaseExpression\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\>\\.$#" + count: 1 + path: src/Components/Lists/ExpressionArray.php + + - + message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|null given\\.$#" + count: 1 + path: src/Components/Lists/ExpressionArray.php + + - + message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|null given\\.$#" + count: 1 + path: src/Components/Lists/ExpressionArray.php + + - + message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#" + count: 1 + path: src/Components/Lists/ExpressionArray.php + - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\LockExpression\\:\\:\\$table \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index f9b5edb1..7020b706 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -136,22 +136,6 @@ - - - $ret - - - Expression[] - - - $expr - $expr - $expr - - - $state === 1 - - value]]> @@ -289,6 +273,22 @@ name]]> + + + $ret + + + Expression[] + + + $expr + $expr + $expr + + + $state === 1 + + $table diff --git a/src/Components/IndexHint.php b/src/Components/IndexHint.php index ec32ede3..d0dd129e 100644 --- a/src/Components/IndexHint.php +++ b/src/Components/IndexHint.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; diff --git a/src/Components/IntoKeyword.php b/src/Components/IntoKeyword.php index 67a467c3..faedc4f6 100644 --- a/src/Components/IntoKeyword.php +++ b/src/Components/IntoKeyword.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; diff --git a/src/Components/ExpressionArray.php b/src/Components/Lists/ExpressionArray.php similarity index 89% rename from src/Components/ExpressionArray.php rename to src/Components/Lists/ExpressionArray.php index dd95a508..962f74a3 100644 --- a/src/Components/ExpressionArray.php +++ b/src/Components/Lists/ExpressionArray.php @@ -2,16 +2,15 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components; +namespace PhpMyAdmin\SqlParser\Components\Lists; -use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Components\CaseExpression; +use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Exceptions\ParserException; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; -use PhpMyAdmin\SqlParser\Translator; -use RuntimeException; use function count; use function implode; @@ -22,7 +21,7 @@ /** * Parses a list of expressions delimited by a comma. */ -final class ExpressionArray implements Component +final class ExpressionArray { /** * @param Parser $parser the parser that serves as context @@ -117,19 +116,9 @@ public static function parse(Parser $parser, TokensList $list, array $options = return $ret; } - public function build(): string - { - throw new RuntimeException(Translator::gettext('Not implemented yet.')); - } - /** @param Expression[] $component the component to be built */ public static function buildAll(array $component): string { return implode(', ', $component); } - - public function __toString(): string - { - return $this->build(); - } } diff --git a/src/Parser.php b/src/Parser.php index 1fbd2a8e..724011b5 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -158,12 +158,12 @@ class Parser 'options' => ['parseField' => 'table'], ], 'ANALYZE' => [ - 'class' => Components\ExpressionArray::class, + 'class' => Components\Lists\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], 'BACKUP' => [ - 'class' => Components\ExpressionArray::class, + 'class' => Components\Lists\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], @@ -172,12 +172,12 @@ class Parser 'field' => 'call', ], 'CHECK' => [ - 'class' => Components\ExpressionArray::class, + 'class' => Components\Lists\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], 'CHECKSUM' => [ - 'class' => Components\ExpressionArray::class, + 'class' => Components\Lists\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], @@ -186,7 +186,7 @@ class Parser 'field' => 'join', ], 'DROP' => [ - 'class' => Components\ExpressionArray::class, + 'class' => Components\Lists\ExpressionArray::class, 'field' => 'fields', 'options' => ['parseField' => 'table'], ], @@ -195,7 +195,7 @@ class Parser 'field' => 'index_hints', ], 'FROM' => [ - 'class' => Components\ExpressionArray::class, + 'class' => Components\Lists\ExpressionArray::class, 'field' => 'from', 'options' => ['field' => 'table'], ], @@ -281,7 +281,7 @@ class Parser 'field' => 'limit', ], 'OPTIMIZE' => [ - 'class' => Components\ExpressionArray::class, + 'class' => Components\Lists\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], @@ -302,12 +302,12 @@ class Parser 'field' => 'renames', ], 'REPAIR' => [ - 'class' => Components\ExpressionArray::class, + 'class' => Components\Lists\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], 'RESTORE' => [ - 'class' => Components\ExpressionArray::class, + 'class' => Components\Lists\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], @@ -316,7 +316,7 @@ class Parser 'field' => 'set', ], 'SELECT' => [ - 'class' => Components\ExpressionArray::class, + 'class' => Components\Lists\ExpressionArray::class, 'field' => 'expr', ], 'TRUNCATE' => [ @@ -325,7 +325,7 @@ class Parser 'options' => ['parseField' => 'table'], ], 'UPDATE' => [ - 'class' => Components\ExpressionArray::class, + 'class' => Components\Lists\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], diff --git a/src/Statements/DeleteStatement.php b/src/Statements/DeleteStatement.php index 8630b27b..c24e0137 100644 --- a/src/Statements/DeleteStatement.php +++ b/src/Statements/DeleteStatement.php @@ -7,10 +7,10 @@ use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Components\Condition; use PhpMyAdmin\SqlParser\Components\Expression; -use PhpMyAdmin\SqlParser\Components\ExpressionArray; use PhpMyAdmin\SqlParser\Components\JoinKeyword; use PhpMyAdmin\SqlParser\Components\Limit; use PhpMyAdmin\SqlParser\Components\Lists\Conditions; +use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\OrderKeyword; use PhpMyAdmin\SqlParser\Parser; diff --git a/src/Statements/LoadStatement.php b/src/Statements/LoadStatement.php index 3c3554f3..11d0129a 100644 --- a/src/Statements/LoadStatement.php +++ b/src/Statements/LoadStatement.php @@ -6,7 +6,7 @@ use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Components\Expression; -use PhpMyAdmin\SqlParser\Components\ExpressionArray; +use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\SetOperation; use PhpMyAdmin\SqlParser\Parser; diff --git a/tests/Components/ExpressionArrayTest.php b/tests/Components/ExpressionArrayTest.php index 9233bab6..3f668a23 100644 --- a/tests/Components/ExpressionArrayTest.php +++ b/tests/Components/ExpressionArrayTest.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\ExpressionArray; +use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Tests\TestCase; From d223cfbf1a681ba43461f491a444737822e39498 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 15:54:13 +0100 Subject: [PATCH 06/17] Split up GroupKeyword Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 17 +++-- psalm-baseline.xml | 23 +++--- src/Components/GroupKeyword.php | 83 ---------------------- src/Components/Lists/GroupKeywords.php | 98 ++++++++++++++++++++++++++ src/Parser.php | 2 +- tests/Components/GroupKeywordTest.php | 3 +- 6 files changed, 124 insertions(+), 102 deletions(-) create mode 100644 src/Components/Lists/GroupKeywords.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index aa0bc968..387ed4c3 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -92,12 +92,7 @@ parameters: - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\GroupKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" - count: 2 - path: src/Components/GroupKeyword.php - - - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\GroupKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" - count: 2 + count: 1 path: src/Components/GroupKeyword.php - @@ -210,6 +205,16 @@ parameters: count: 1 path: src/Components/Lists/ExpressionArray.php + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\GroupKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" + count: 1 + path: src/Components/Lists/GroupKeywords.php + + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\GroupKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" + count: 2 + path: src/Components/Lists/GroupKeywords.php + - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\LockExpression\\:\\:\\$table \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 7020b706..9d1c4210 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -154,21 +154,10 @@ $expr - Expression::parse($parser, $list) $type - - $state === 1 - - - expr)]]> - expr)]]> - - - $options - @@ -289,6 +278,18 @@ $state === 1 + + + Expression::parse($parser, $list) + + + expr)]]> + expr)]]> + + + $options + + $table diff --git a/src/Components/GroupKeyword.php b/src/Components/GroupKeyword.php index 403e8d05..cfec7c09 100644 --- a/src/Components/GroupKeyword.php +++ b/src/Components/GroupKeyword.php @@ -5,11 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; -use PhpMyAdmin\SqlParser\Parser; -use PhpMyAdmin\SqlParser\TokensList; -use PhpMyAdmin\SqlParser\TokenType; -use function implode; use function trim; /** @@ -33,90 +29,11 @@ public function __construct(Expression|null $expr = null) $this->expr = $expr; } - /** - * @param Parser $parser the parser that serves as context - * @param TokensList $list the list of tokens that are being parsed - * @param array $options parameters for parsing - * - * @return GroupKeyword[] - */ - public static function parse(Parser $parser, TokensList $list, array $options = []): array - { - $ret = []; - - $expr = new static(); - - /** - * The state of the parser. - * - * Below are the states of the parser. - * - * 0 --------------------[ expression ]-------------------> 1 - * - * 1 ------------------------[ , ]------------------------> 0 - * 1 -------------------[ ASC / DESC ]--------------------> 1 - */ - $state = 0; - - for (; $list->idx < $list->count; ++$list->idx) { - /** - * Token parsed at this moment. - */ - $token = $list->tokens[$list->idx]; - - // End of statement. - if ($token->type === TokenType::Delimiter) { - break; - } - - // Skipping whitespaces and comments. - if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { - continue; - } - - if ($state === 0) { - $expr->expr = Expression::parse($parser, $list); - $state = 1; - } elseif ($state === 1) { - if ( - ($token->type === TokenType::Keyword) - && (($token->keyword === 'ASC') || ($token->keyword === 'DESC')) - ) { - $expr->type = $token->keyword; - } elseif (($token->type === TokenType::Operator) && ($token->value === ',')) { - if (! empty($expr->expr)) { - $ret[] = $expr; - } - - $expr = new static(); - $state = 0; - } else { - break; - } - } - } - - // Last iteration was not processed. - if (! empty($expr->expr)) { - $ret[] = $expr; - } - - --$list->idx; - - return $ret; - } - public function build(): string { return trim((string) $this->expr); } - /** @param GroupKeyword[] $component the component to be built */ - public static function buildAll(array $component): string - { - return implode(', ', $component); - } - public function __toString(): string { return $this->build(); diff --git a/src/Components/Lists/GroupKeywords.php b/src/Components/Lists/GroupKeywords.php new file mode 100644 index 00000000..f5872b33 --- /dev/null +++ b/src/Components/Lists/GroupKeywords.php @@ -0,0 +1,98 @@ + $options parameters for parsing + * + * @return GroupKeyword[] + */ + public static function parse(Parser $parser, TokensList $list, array $options = []): array + { + $ret = []; + + $expr = new GroupKeyword(); + + /** + * The state of the parser. + * + * Below are the states of the parser. + * + * 0 --------------------[ expression ]-------------------> 1 + * + * 1 ------------------------[ , ]------------------------> 0 + * 1 -------------------[ ASC / DESC ]--------------------> 1 + */ + $state = 0; + + for (; $list->idx < $list->count; ++$list->idx) { + /** + * Token parsed at this moment. + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === TokenType::Delimiter) { + break; + } + + // Skipping whitespaces and comments. + if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { + continue; + } + + if ($state === 0) { + $expr->expr = Expression::parse($parser, $list); + $state = 1; + } elseif ($state === 1) { + if ( + ($token->type === TokenType::Keyword) + && (($token->keyword === 'ASC') || ($token->keyword === 'DESC')) + ) { + $expr->type = $token->keyword; + } elseif (($token->type === TokenType::Operator) && ($token->value === ',')) { + if (! empty($expr->expr)) { + $ret[] = $expr; + } + + $expr = new GroupKeyword(); + $state = 0; + } else { + break; + } + } + } + + // Last iteration was not processed. + if (! empty($expr->expr)) { + $ret[] = $expr; + } + + --$list->idx; + + return $ret; + } + + /** @param GroupKeyword[] $component the component to be built */ + public static function buildAll(array $component): string + { + return implode(', ', $component); + } +} diff --git a/src/Parser.php b/src/Parser.php index 724011b5..69456b36 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -200,7 +200,7 @@ class Parser 'options' => ['field' => 'table'], ], 'GROUP BY' => [ - 'class' => Components\GroupKeyword::class, + 'class' => Components\Lists\GroupKeywords::class, 'field' => 'group', ], 'HAVING' => [ diff --git a/tests/Components/GroupKeywordTest.php b/tests/Components/GroupKeywordTest.php index 3001ac6a..2344790c 100644 --- a/tests/Components/GroupKeywordTest.php +++ b/tests/Components/GroupKeywordTest.php @@ -7,6 +7,7 @@ use Generator; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\GroupKeyword; +use PhpMyAdmin\SqlParser\Components\Lists\GroupKeywords; use PhpMyAdmin\SqlParser\Tests\TestCase; use PHPUnit\Framework\Attributes\DataProvider; @@ -56,7 +57,7 @@ public static function provideExpressions(): Generator public function testBuild(GroupKeyword|array $component, string $expected): void { if (is_array($component)) { - $this->assertSame($expected, GroupKeyword::buildAll($component)); + $this->assertSame($expected, GroupKeywords::buildAll($component)); } else { $this->assertSame($expected, $component->build()); } From 7939ab2c9b4ff160b02a0cb84f39fd8465c0e28a Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 15:57:31 +0100 Subject: [PATCH 07/17] Split up IndexHint Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 10 +- psalm-baseline.xml | 11 ++- src/Components/IndexHint.php | 130 ------------------------- src/Components/Lists/IndexHints.php | 142 ++++++++++++++++++++++++++++ src/Parser.php | 6 +- 5 files changed, 158 insertions(+), 141 deletions(-) create mode 100644 src/Components/Lists/IndexHints.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 387ed4c3..59ff3734 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -95,11 +95,6 @@ parameters: count: 1 path: src/Components/GroupKeyword.php - - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\IndexHint\\:\\:\\$type \\(string\\|null\\) does not accept mixed\\.$#" - count: 1 - path: src/Components/IndexHint.php - - message: "#^Cannot access property \\$values on array\\\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\.$#" count: 1 @@ -215,6 +210,11 @@ parameters: count: 2 path: src/Components/Lists/GroupKeywords.php + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\IndexHint\\:\\:\\$type \\(string\\|null\\) does not accept mixed\\.$#" + count: 1 + path: src/Components/Lists/IndexHints.php + - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\LockExpression\\:\\:\\$table \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 9d1c4210..3aa1b5e4 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -160,9 +160,6 @@ - - type]]> - indexOrKey]]> type]]> @@ -290,6 +287,14 @@ $options + + + type]]> + + + buildAll + + $table diff --git a/src/Components/IndexHint.php b/src/Components/IndexHint.php index d0dd129e..efa5c30a 100644 --- a/src/Components/IndexHint.php +++ b/src/Components/IndexHint.php @@ -5,12 +5,6 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; -use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; -use PhpMyAdmin\SqlParser\Parser; -use PhpMyAdmin\SqlParser\TokensList; -use PhpMyAdmin\SqlParser\TokenType; - -use function implode; /** * Parses an Index hint. @@ -57,124 +51,6 @@ public function __construct( $this->indexes = $indexes; } - /** - * @param Parser $parser the parser that serves as context - * @param TokensList $list the list of tokens that are being parsed - * @param array $options parameters for parsing - * - * @return IndexHint[] - */ - public static function parse(Parser $parser, TokensList $list, array $options = []): array - { - $ret = []; - $expr = new static(); - $expr->type = $options['type'] ?? null; - /** - * The state of the parser. - * - * Below are the states of the parser. - * 0 ----------------- [ USE/IGNORE/FORCE ]-----------------> 1 - * 1 -------------------- [ INDEX/KEY ] --------------------> 2 - * 2 ----------------------- [ FOR ] -----------------------> 3 - * 2 -------------------- [ expr_list ] --------------------> 0 - * 3 -------------- [ JOIN/GROUP BY/ORDER BY ] -------------> 4 - * 4 -------------------- [ expr_list ] --------------------> 0 - */ - $state = 0; - - // By design, the parser will parse first token after the keyword. So, the keyword - // must be analyzed too, in order to determine the type of this index hint. - if ($list->idx > 0) { - --$list->idx; - } - - for (; $list->idx < $list->count; ++$list->idx) { - /** - * Token parsed at this moment. - */ - $token = $list->tokens[$list->idx]; - - // End of statement. - if ($token->type === TokenType::Delimiter) { - break; - } - - // Skipping whitespaces and comments. - if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { - continue; - } - - switch ($state) { - case 0: - if ($token->type === TokenType::Keyword) { - if ($token->keyword !== 'USE' && $token->keyword !== 'IGNORE' && $token->keyword !== 'FORCE') { - break 2; - } - - $expr->type = $token->keyword; - $state = 1; - } - - break; - case 1: - if ($token->type === TokenType::Keyword) { - if ($token->keyword === 'INDEX' || $token->keyword === 'KEY') { - $expr->indexOrKey = $token->keyword; - } else { - $parser->error('Unexpected keyword.', $token); - } - - $state = 2; - } else { - // we expect the token to be a keyword - $parser->error('Unexpected token.', $token); - } - - break; - case 2: - if ($token->type === TokenType::Keyword && $token->keyword === 'FOR') { - $state = 3; - } else { - $expr->indexes = ExpressionArray::parse($parser, $list); - $state = 0; - $ret[] = $expr; - $expr = new static(); - } - - break; - case 3: - if ($token->type === TokenType::Keyword) { - if ( - $token->keyword === 'JOIN' - || $token->keyword === 'GROUP BY' - || $token->keyword === 'ORDER BY' - ) { - $expr->for = $token->keyword; - } else { - $parser->error('Unexpected keyword.', $token); - } - - $state = 4; - } else { - // we expect the token to be a keyword - $parser->error('Unexpected token.', $token); - } - - break; - case 4: - $expr->indexes = ExpressionArray::parse($parser, $list); - $state = 0; - $ret[] = $expr; - $expr = new static(); - break; - } - } - - --$list->idx; - - return $ret; - } - public function build(): string { $ret = $this->type . ' ' . $this->indexOrKey . ' '; @@ -185,12 +61,6 @@ public function build(): string return $ret . Expression::buildAll($this->indexes); } - /** @param IndexHint[] $component the component to be built */ - public static function buildAll(array $component): string - { - return implode(' ', $component); - } - public function __toString(): string { return $this->build(); diff --git a/src/Components/Lists/IndexHints.php b/src/Components/Lists/IndexHints.php new file mode 100644 index 00000000..11a1d66e --- /dev/null +++ b/src/Components/Lists/IndexHints.php @@ -0,0 +1,142 @@ + $options parameters for parsing + * + * @return IndexHint[] + */ + public static function parse(Parser $parser, TokensList $list, array $options = []): array + { + $ret = []; + $expr = new IndexHint(); + $expr->type = $options['type'] ?? null; + /** + * The state of the parser. + * + * Below are the states of the parser. + * 0 ----------------- [ USE/IGNORE/FORCE ]-----------------> 1 + * 1 -------------------- [ INDEX/KEY ] --------------------> 2 + * 2 ----------------------- [ FOR ] -----------------------> 3 + * 2 -------------------- [ expr_list ] --------------------> 0 + * 3 -------------- [ JOIN/GROUP BY/ORDER BY ] -------------> 4 + * 4 -------------------- [ expr_list ] --------------------> 0 + */ + $state = 0; + + // By design, the parser will parse first token after the keyword. So, the keyword + // must be analyzed too, in order to determine the type of this index hint. + if ($list->idx > 0) { + --$list->idx; + } + + for (; $list->idx < $list->count; ++$list->idx) { + /** + * Token parsed at this moment. + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === TokenType::Delimiter) { + break; + } + + // Skipping whitespaces and comments. + if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { + continue; + } + + switch ($state) { + case 0: + if ($token->type === TokenType::Keyword) { + if ($token->keyword !== 'USE' && $token->keyword !== 'IGNORE' && $token->keyword !== 'FORCE') { + break 2; + } + + $expr->type = $token->keyword; + $state = 1; + } + + break; + case 1: + if ($token->type === TokenType::Keyword) { + if ($token->keyword === 'INDEX' || $token->keyword === 'KEY') { + $expr->indexOrKey = $token->keyword; + } else { + $parser->error('Unexpected keyword.', $token); + } + + $state = 2; + } else { + // we expect the token to be a keyword + $parser->error('Unexpected token.', $token); + } + + break; + case 2: + if ($token->type === TokenType::Keyword && $token->keyword === 'FOR') { + $state = 3; + } else { + $expr->indexes = ExpressionArray::parse($parser, $list); + $state = 0; + $ret[] = $expr; + $expr = new IndexHint(); + } + + break; + case 3: + if ($token->type === TokenType::Keyword) { + if ( + $token->keyword === 'JOIN' + || $token->keyword === 'GROUP BY' + || $token->keyword === 'ORDER BY' + ) { + $expr->for = $token->keyword; + } else { + $parser->error('Unexpected keyword.', $token); + } + + $state = 4; + } else { + // we expect the token to be a keyword + $parser->error('Unexpected token.', $token); + } + + break; + case 4: + $expr->indexes = ExpressionArray::parse($parser, $list); + $state = 0; + $ret[] = $expr; + $expr = new IndexHint(); + break; + } + } + + --$list->idx; + + return $ret; + } + + /** @param IndexHint[] $component the component to be built */ + public static function buildAll(array $component): string + { + return implode(' ', $component); + } +} diff --git a/src/Parser.php b/src/Parser.php index 69456b36..1bc55e32 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -191,7 +191,7 @@ class Parser 'options' => ['parseField' => 'table'], ], 'FORCE' => [ - 'class' => Components\IndexHint::class, + 'class' => Components\Lists\IndexHints::class, 'field' => 'index_hints', ], 'FROM' => [ @@ -208,7 +208,7 @@ class Parser 'field' => 'having', ], 'IGNORE' => [ - 'class' => Components\IndexHint::class, + 'class' => Components\Lists\IndexHints::class, 'field' => 'index_hints', ], 'INTO' => [ @@ -330,7 +330,7 @@ class Parser 'options' => ['parseField' => 'table'], ], 'USE' => [ - 'class' => Components\IndexHint::class, + 'class' => Components\Lists\IndexHints::class, 'field' => 'index_hints', ], 'VALUE' => [ From 549fc8f933c78623636c1e57e27cc8a9be817fe1 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 16:09:55 +0100 Subject: [PATCH 08/17] Split up JoinKeyword Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 17 ++-- psalm-baseline.xml | 49 +++++----- src/Components/JoinKeyword.php | 134 +------------------------ src/Components/Lists/JoinKeywords.php | 135 ++++++++++++++++++++++++++ src/Parser.php | 30 +++--- src/Statements/DeleteStatement.php | 5 +- tests/Components/JoinKeywordTest.php | 10 +- 7 files changed, 198 insertions(+), 182 deletions(-) create mode 100644 src/Components/Lists/JoinKeywords.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 59ff3734..63484f82 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -112,7 +112,7 @@ parameters: - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\JoinKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" - count: 2 + count: 1 path: src/Components/JoinKeyword.php - @@ -130,11 +130,6 @@ parameters: count: 1 path: src/Components/JoinKeyword.php - - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\JoinKeyword\\:\\:\\$using \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\) does not accept array\\\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\.$#" - count: 1 - path: src/Components/JoinKeyword.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\JoinKeyword\\:\\:\\$using \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\) in empty\\(\\) is not falsy\\.$#" count: 1 @@ -215,6 +210,16 @@ parameters: count: 1 path: src/Components/Lists/IndexHints.php + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\JoinKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" + count: 1 + path: src/Components/Lists/JoinKeywords.php + + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\JoinKeyword\\:\\:\\$using \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\) does not accept array\\\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\.$#" + count: 1 + path: src/Components/Lists/JoinKeywords.php + - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\LockExpression\\:\\:\\$table \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 3aa1b5e4..ddb8c897 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -187,36 +187,18 @@ - - keyword]]]> - keyword]]]> - - type, self::JOINS)]]> + type, self::JOINS)]]> - - ArrayObj::parse($parser, $list) - $expr $on $type $using - 'table'])]]> - - $state === 4 - - using)]]> + using)]]> - - keyword])]]> - keyword])]]> - - - $options - @@ -291,9 +273,30 @@ type]]> - - buildAll - + + + + keyword]]]> + keyword]]]> + + + ArrayObj::parse($parser, $list) + + + 'table'])]]> + + + keyword])]]> + keyword])]]> + + + $options + + + $state + $state + $state + diff --git a/src/Components/JoinKeyword.php b/src/Components/JoinKeyword.php index 6ee26e56..29a551a4 100644 --- a/src/Components/JoinKeyword.php +++ b/src/Components/JoinKeyword.php @@ -6,14 +6,8 @@ use PhpMyAdmin\SqlParser\Component; use PhpMyAdmin\SqlParser\Components\Lists\Conditions; -use PhpMyAdmin\SqlParser\Parser; -use PhpMyAdmin\SqlParser\TokensList; -use PhpMyAdmin\SqlParser\TokenType; -use PhpMyAdmin\SqlParser\Translator; -use RuntimeException; use function array_search; -use function implode; /** * `JOIN` keyword parser. @@ -91,133 +85,11 @@ public function __construct( $this->using = $using; } - /** - * @param Parser $parser the parser that serves as context - * @param TokensList $list the list of tokens that are being parsed - * @param array $options parameters for parsing - * - * @return JoinKeyword[] - */ - public static function parse(Parser $parser, TokensList $list, array $options = []): array - { - $ret = []; - - $expr = new static(); - - /** - * The state of the parser. - * - * Below are the states of the parser. - * - * 0 -----------------------[ JOIN ]----------------------> 1 - * - * 1 -----------------------[ expr ]----------------------> 2 - * - * 2 ------------------------[ ON ]-----------------------> 3 - * 2 -----------------------[ USING ]---------------------> 4 - * - * 3 --------------------[ conditions ]-------------------> 0 - * - * 4 ----------------------[ columns ]--------------------> 0 - */ - $state = 0; - - // By design, the parser will parse first token after the keyword. - // In this case, the keyword must be analyzed too, in order to determine - // the type of this join. - if ($list->idx > 0) { - --$list->idx; - } - - for (; $list->idx < $list->count; ++$list->idx) { - /** - * Token parsed at this moment. - */ - $token = $list->tokens[$list->idx]; - - // End of statement. - if ($token->type === TokenType::Delimiter) { - break; - } - - // Skipping whitespaces and comments. - if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { - continue; - } - - if ($state === 0) { - if (($token->type !== TokenType::Keyword) || empty(self::JOINS[$token->keyword])) { - break; - } - - $expr->type = self::JOINS[$token->keyword]; - $state = 1; - } elseif ($state === 1) { - $expr->expr = Expression::parse($parser, $list, ['field' => 'table']); - $state = 2; - } elseif ($state === 2) { - if ($token->type === TokenType::Keyword) { - switch ($token->keyword) { - case 'ON': - $state = 3; - break; - case 'USING': - $state = 4; - break; - default: - if (empty(self::JOINS[$token->keyword])) { - /* Next clause is starting */ - break 2; - } - - $ret[] = $expr; - $expr = new static(); - $expr->type = self::JOINS[$token->keyword]; - $state = 1; - - break; - } - } - } elseif ($state === 3) { - $expr->on = Conditions::parse($parser, $list); - $ret[] = $expr; - $expr = new static(); - $state = 0; - } elseif ($state === 4) { - $expr->using = ArrayObj::parse($parser, $list); - $ret[] = $expr; - $expr = new static(); - $state = 0; - } - } - - if (! empty($expr->type)) { - $ret[] = $expr; - } - - --$list->idx; - - return $ret; - } - public function build(): string { - throw new RuntimeException(Translator::gettext('Not implemented yet.')); - } - - /** @param JoinKeyword[] $component the component to be built */ - public static function buildAll(array $component): string - { - $ret = []; - foreach ($component as $c) { - $ret[] = array_search($c->type, self::JOINS) . ' ' . $c->expr - . (! empty($c->on) - ? ' ON ' . Conditions::buildAll($c->on) : '') - . (! empty($c->using) - ? ' USING ' . $c->using->build() : ''); - } - - return implode(' ', $ret); + return array_search($this->type, self::JOINS) . ' ' . $this->expr + . (! empty($this->on) ? ' ON ' . Conditions::buildAll($this->on) : '') + . (! empty($this->using) ? ' USING ' . $this->using->build() : ''); } public function __toString(): string diff --git a/src/Components/Lists/JoinKeywords.php b/src/Components/Lists/JoinKeywords.php new file mode 100644 index 00000000..834181b9 --- /dev/null +++ b/src/Components/Lists/JoinKeywords.php @@ -0,0 +1,135 @@ + $options parameters for parsing + * + * @return JoinKeyword[] + */ + public static function parse(Parser $parser, TokensList $list, array $options = []): array + { + $ret = []; + + $expr = new JoinKeyword(); + + /** + * The state of the parser. + * + * Below are the states of the parser. + * + * 0 -----------------------[ JOIN ]----------------------> 1 + * + * 1 -----------------------[ expr ]----------------------> 2 + * + * 2 ------------------------[ ON ]-----------------------> 3 + * 2 -----------------------[ USING ]---------------------> 4 + * + * 3 --------------------[ conditions ]-------------------> 0 + * + * 4 ----------------------[ columns ]--------------------> 0 + */ + $state = 0; + + // By design, the parser will parse first token after the keyword. + // In this case, the keyword must be analyzed too, in order to determine + // the type of this join. + if ($list->idx > 0) { + --$list->idx; + } + + for (; $list->idx < $list->count; ++$list->idx) { + /** + * Token parsed at this moment. + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === TokenType::Delimiter) { + break; + } + + // Skipping whitespaces and comments. + if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { + continue; + } + + if ($state === 0) { + if (($token->type !== TokenType::Keyword) || empty(JoinKeyword::JOINS[$token->keyword])) { + break; + } + + $expr->type = JoinKeyword::JOINS[$token->keyword]; + $state = 1; + } elseif ($state === 1) { + $expr->expr = Expression::parse($parser, $list, ['field' => 'table']); + $state = 2; + } elseif ($state === 2) { + if ($token->type === TokenType::Keyword) { + switch ($token->keyword) { + case 'ON': + $state = 3; + break; + case 'USING': + $state = 4; + break; + default: + if (empty(JoinKeyword::JOINS[$token->keyword])) { + /* Next clause is starting */ + break 2; + } + + $ret[] = $expr; + $expr = new JoinKeyword(); + $expr->type = JoinKeyword::JOINS[$token->keyword]; + $state = 1; + + break; + } + } + } elseif ($state === 3) { + $expr->on = Conditions::parse($parser, $list); + $ret[] = $expr; + $expr = new JoinKeyword(); + $state = 0; + } elseif ($state === 4) { + $expr->using = ArrayObj::parse($parser, $list); + $ret[] = $expr; + $expr = new JoinKeyword(); + $state = 0; + } + } + + if (! empty($expr->type)) { + $ret[] = $expr; + } + + --$list->idx; + + return $ret; + } + + /** @param JoinKeyword[] $component the component to be built */ + public static function buildAll(array $component): string + { + return implode(' ', $component); + } +} diff --git a/src/Parser.php b/src/Parser.php index 1bc55e32..fc60f8e7 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -182,7 +182,7 @@ class Parser 'options' => ['parseField' => 'table'], ], 'CROSS JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'DROP' => [ @@ -216,15 +216,15 @@ class Parser 'field' => 'into', ], 'JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'LEFT JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'LEFT OUTER JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'ON' => [ @@ -233,47 +233,47 @@ class Parser 'options' => ['parseField' => 'table'], ], 'RIGHT JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'RIGHT OUTER JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'INNER JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'FULL JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'FULL OUTER JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'NATURAL JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'NATURAL LEFT JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'NATURAL RIGHT JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'NATURAL LEFT OUTER JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'NATURAL RIGHT OUTER JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'STRAIGHT_JOIN' => [ - 'class' => Components\JoinKeyword::class, + 'class' => Components\Lists\JoinKeywords::class, 'field' => 'join', ], 'LIMIT' => [ diff --git a/src/Statements/DeleteStatement.php b/src/Statements/DeleteStatement.php index c24e0137..e0063c96 100644 --- a/src/Statements/DeleteStatement.php +++ b/src/Statements/DeleteStatement.php @@ -11,6 +11,7 @@ use PhpMyAdmin\SqlParser\Components\Limit; use PhpMyAdmin\SqlParser\Components\Lists\Conditions; use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; +use PhpMyAdmin\SqlParser\Components\Lists\JoinKeywords; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\OrderKeyword; use PhpMyAdmin\SqlParser\Parser; @@ -166,7 +167,7 @@ public function build(): string } if ($this->join !== null && $this->join !== []) { - $ret .= ' ' . JoinKeyword::buildAll($this->join); + $ret .= ' ' . JoinKeywords::buildAll($this->join); } if ($this->using !== null && $this->using !== []) { @@ -265,7 +266,7 @@ public function parse(Parser $parser, TokensList $list): void if ($token->type === TokenType::Keyword) { if (stripos($token->keyword, 'JOIN') !== false) { ++$list->idx; - $this->join = JoinKeyword::parse($parser, $list); + $this->join = JoinKeywords::parse($parser, $list); // remain in state = 2 } else { diff --git a/tests/Components/JoinKeywordTest.php b/tests/Components/JoinKeywordTest.php index 705d516d..45c44662 100644 --- a/tests/Components/JoinKeywordTest.php +++ b/tests/Components/JoinKeywordTest.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\JoinKeyword; +use PhpMyAdmin\SqlParser\Components\Lists\JoinKeywords; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Tests\TestCase; @@ -12,7 +12,7 @@ class JoinKeywordTest extends TestCase { public function testParseIncomplete(): void { - $component = JoinKeyword::parse(new Parser(), $this->getTokensList('JOIN a')); + $component = JoinKeywords::parse(new Parser(), $this->getTokensList('JOIN a')); $this->assertCount(1, $component); $this->assertEquals('a', $component[0]->expr->expr); $this->assertNull($component[0]->on); @@ -21,7 +21,7 @@ public function testParseIncomplete(): void public function testParseIncompleteUsing(): void { - $component = JoinKeyword::parse(new Parser(), $this->getTokensList('JOIN table2 USING (id)')); + $component = JoinKeywords::parse(new Parser(), $this->getTokensList('JOIN table2 USING (id)')); $this->assertCount(1, $component); $this->assertEquals('table2', $component[0]->expr->expr); $this->assertNull($component[0]->on); @@ -30,7 +30,7 @@ public function testParseIncompleteUsing(): void public function testBuildAll(): void { - $component = JoinKeyword::parse( + $component = JoinKeywords::parse( new Parser(), $this->getTokensList( 'LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4) ' . @@ -40,7 +40,7 @@ public function testBuildAll(): void $this->assertEquals( 'LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4) ' . 'ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)', - JoinKeyword::buildAll($component), + JoinKeywords::buildAll($component), ); } } From 420d37013ae0a9d57f7a891c68e2de7bd4132992 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 16:14:05 +0100 Subject: [PATCH 09/17] Split up OrderKeyword Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 17 +++-- psalm-baseline.xml | 57 +++++++++++---- src/Components/Lists/OrderKeywords.php | 98 ++++++++++++++++++++++++++ src/Components/OrderKeyword.php | 84 ---------------------- src/Parser.php | 2 +- src/Statements/DeleteStatement.php | 7 +- tests/Components/OrderKeywordTest.php | 3 +- 7 files changed, 159 insertions(+), 109 deletions(-) create mode 100644 src/Components/Lists/OrderKeywords.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 63484f82..be8a73cf 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -220,6 +220,16 @@ parameters: count: 1 path: src/Components/Lists/JoinKeywords.php + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\OrderKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" + count: 1 + path: src/Components/Lists/OrderKeywords.php + + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\OrderKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" + count: 2 + path: src/Components/Lists/OrderKeywords.php + - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\LockExpression\\:\\:\\$table \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 @@ -277,12 +287,7 @@ parameters: - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\OrderKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" - count: 2 - path: src/Components/OrderKeyword.php - - - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\OrderKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" - count: 2 + count: 1 path: src/Components/OrderKeyword.php - diff --git a/psalm-baseline.xml b/psalm-baseline.xml index ddb8c897..6de30b65 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -298,6 +298,22 @@ $state + + + OrderKeyword[] + string + + + OrderKeyword[] + OrderKeyword[] + + + $component + $list + $options + $parser + + $table @@ -394,20 +410,9 @@ - - $expr - Expression::parse($parser, $list) - - - $state === 1 - - - expr)]]> - expr)]]> - - - $options - + + + @@ -968,6 +973,10 @@ $partition + + array|null + public array|null $order = null; + @@ -1084,6 +1093,10 @@ join)]]> + + array|null + public array|null $order = null; + @@ -1122,6 +1135,10 @@ $set $where + + array|null + public array|null $order = null; + @@ -1615,6 +1632,18 @@ assertNotNull + + + + + + OrderKeyword + OrderKeyword + + expr->expr]]> diff --git a/src/Components/Lists/OrderKeywords.php b/src/Components/Lists/OrderKeywords.php new file mode 100644 index 00000000..7f862920 --- /dev/null +++ b/src/Components/Lists/OrderKeywords.php @@ -0,0 +1,98 @@ + $options parameters for parsing + * + * @return OrderKeyword[] + */ + public static function parse(Parser $parser, TokensList $list, array $options = []): array + { + $ret = []; + + $expr = new OrderKeyword(); + + /** + * The state of the parser. + * + * Below are the states of the parser. + * + * 0 --------------------[ expression ]-------------------> 1 + * + * 1 ------------------------[ , ]------------------------> 0 + * 1 -------------------[ ASC / DESC ]--------------------> 1 + */ + $state = 0; + + for (; $list->idx < $list->count; ++$list->idx) { + /** + * Token parsed at this moment. + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === TokenType::Delimiter) { + break; + } + + // Skipping whitespaces and comments. + if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { + continue; + } + + if ($state === 0) { + $expr->expr = Expression::parse($parser, $list); + $state = 1; + } elseif ($state === 1) { + if ( + ($token->type === TokenType::Keyword) + && (($token->keyword === 'ASC') || ($token->keyword === 'DESC')) + ) { + $expr->type = $token->keyword; + } elseif (($token->type === TokenType::Operator) && ($token->value === ',')) { + if (! empty($expr->expr)) { + $ret[] = $expr; + } + + $expr = new OrderKeyword(); + $state = 0; + } else { + break; + } + } + } + + // Last iteration was not processed. + if (! empty($expr->expr)) { + $ret[] = $expr; + } + + --$list->idx; + + return $ret; + } + + /** @param OrderKeyword[] $component the component to be built */ + public static function buildAll(array $component): string + { + return implode(', ', $component); + } +} diff --git a/src/Components/OrderKeyword.php b/src/Components/OrderKeyword.php index 7ec76356..caee43ac 100644 --- a/src/Components/OrderKeyword.php +++ b/src/Components/OrderKeyword.php @@ -5,11 +5,6 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; -use PhpMyAdmin\SqlParser\Parser; -use PhpMyAdmin\SqlParser\TokensList; -use PhpMyAdmin\SqlParser\TokenType; - -use function implode; /** * `ORDER BY` keyword parser. @@ -40,90 +35,11 @@ public function __construct(Expression|null $expr = null, string $type = 'ASC') $this->type = $type; } - /** - * @param Parser $parser the parser that serves as context - * @param TokensList $list the list of tokens that are being parsed - * @param array $options parameters for parsing - * - * @return OrderKeyword[] - */ - public static function parse(Parser $parser, TokensList $list, array $options = []): array - { - $ret = []; - - $expr = new static(); - - /** - * The state of the parser. - * - * Below are the states of the parser. - * - * 0 --------------------[ expression ]-------------------> 1 - * - * 1 ------------------------[ , ]------------------------> 0 - * 1 -------------------[ ASC / DESC ]--------------------> 1 - */ - $state = 0; - - for (; $list->idx < $list->count; ++$list->idx) { - /** - * Token parsed at this moment. - */ - $token = $list->tokens[$list->idx]; - - // End of statement. - if ($token->type === TokenType::Delimiter) { - break; - } - - // Skipping whitespaces and comments. - if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { - continue; - } - - if ($state === 0) { - $expr->expr = Expression::parse($parser, $list); - $state = 1; - } elseif ($state === 1) { - if ( - ($token->type === TokenType::Keyword) - && (($token->keyword === 'ASC') || ($token->keyword === 'DESC')) - ) { - $expr->type = $token->keyword; - } elseif (($token->type === TokenType::Operator) && ($token->value === ',')) { - if (! empty($expr->expr)) { - $ret[] = $expr; - } - - $expr = new static(); - $state = 0; - } else { - break; - } - } - } - - // Last iteration was not processed. - if (! empty($expr->expr)) { - $ret[] = $expr; - } - - --$list->idx; - - return $ret; - } - public function build(): string { return $this->expr . ' ' . $this->type; } - /** @param OrderKeyword[] $component the component to be built */ - public static function buildAll(array $component): string - { - return implode(', ', $component); - } - public function __toString(): string { return $this->build(); diff --git a/src/Parser.php b/src/Parser.php index fc60f8e7..ba6a17cd 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -286,7 +286,7 @@ class Parser 'options' => ['parseField' => 'table'], ], 'ORDER BY' => [ - 'class' => Components\OrderKeyword::class, + 'class' => Components\Lists\OrderKeywords::class, 'field' => 'order', ], 'PARTITION' => [ diff --git a/src/Statements/DeleteStatement.php b/src/Statements/DeleteStatement.php index e0063c96..d06b8fac 100644 --- a/src/Statements/DeleteStatement.php +++ b/src/Statements/DeleteStatement.php @@ -12,6 +12,7 @@ use PhpMyAdmin\SqlParser\Components\Lists\Conditions; use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; use PhpMyAdmin\SqlParser\Components\Lists\JoinKeywords; +use PhpMyAdmin\SqlParser\Components\Lists\OrderKeywords; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\OrderKeyword; use PhpMyAdmin\SqlParser\Parser; @@ -179,7 +180,7 @@ public function build(): string } if ($this->order !== null && $this->order !== []) { - $ret .= ' ORDER BY ' . OrderKeyword::buildAll($this->order); + $ret .= ' ORDER BY ' . OrderKeywords::buildAll($this->order); } if ($this->limit !== null && strlen((string) $this->limit) > 0) { @@ -285,7 +286,7 @@ public function parse(Parser $parser, TokensList $list): void break; case 'ORDER BY': ++$list->idx; // Skip 'ORDER BY' - $this->order = OrderKeyword::parse($parser, $list); + $this->order = OrderKeywords::parse($parser, $list); $state = 5; break; case 'LIMIT': @@ -323,7 +324,7 @@ public function parse(Parser $parser, TokensList $list): void switch ($token->keyword) { case 'ORDER BY': ++$list->idx; // Skip 'ORDER BY' - $this->order = OrderKeyword::parse($parser, $list); + $this->order = OrderKeywords::parse($parser, $list); $state = 5; break; case 'LIMIT': diff --git a/tests/Components/OrderKeywordTest.php b/tests/Components/OrderKeywordTest.php index ec394bdb..454899cd 100644 --- a/tests/Components/OrderKeywordTest.php +++ b/tests/Components/OrderKeywordTest.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; use PhpMyAdmin\SqlParser\Components\Expression; +use PhpMyAdmin\SqlParser\Components\Lists\OrderKeywords; use PhpMyAdmin\SqlParser\Components\OrderKeyword; use PhpMyAdmin\SqlParser\Tests\TestCase; @@ -13,7 +14,7 @@ class OrderKeywordTest extends TestCase public function testBuildAll(): void { $this->assertEquals( - OrderKeyword::buildAll( + OrderKeywords::buildAll( [ new OrderKeyword(new Expression('a'), 'ASC'), new OrderKeyword(new Expression('b'), 'DESC'), From 801358ce2160350b3ce4bb3f5d5dcf87b01d6209 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 16:17:12 +0100 Subject: [PATCH 10/17] Split up ParameterDefinition Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 29 +++-- psalm-baseline.xml | 75 ++++-------- src/Components/Lists/ParameterDefinitions.php | 111 ++++++++++++++++++ src/Components/ParameterDefinition.php | 96 --------------- src/Statements/CreateStatement.php | 5 +- src/Utils/Routine.php | 4 +- tests/Builder/CreateStatementTest.php | 6 +- tests/Components/ParameterDefinitionTest.php | 6 +- 8 files changed, 163 insertions(+), 169 deletions(-) create mode 100644 src/Components/Lists/ParameterDefinitions.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index be8a73cf..025b4ef1 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -230,6 +230,21 @@ parameters: count: 2 path: src/Components/Lists/OrderKeywords.php + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$name \\(string\\) does not accept mixed\\.$#" + count: 1 + path: src/Components/Lists/ParameterDefinitions.php + + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$name \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: src/Components/Lists/ParameterDefinitions.php + + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$type \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\DataType\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\DataType\\|null\\.$#" + count: 1 + path: src/Components/Lists/ParameterDefinitions.php + - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\LockExpression\\:\\:\\$table \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 @@ -295,24 +310,14 @@ parameters: count: 1 path: src/Components/ParameterDefinition.php - - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$name \\(string\\) does not accept mixed\\.$#" - count: 1 - path: src/Components/ParameterDefinition.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$name \\(string\\) does not accept string\\|null\\.$#" count: 1 path: src/Components/ParameterDefinition.php - - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$name \\(string\\) in isset\\(\\) is not nullable\\.$#" - count: 1 - path: src/Components/ParameterDefinition.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$type \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\DataType\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\DataType\\|null\\.$#" - count: 2 + count: 1 path: src/Components/ParameterDefinition.php - @@ -611,7 +616,7 @@ parameters: path: src/Statements/CreateStatement.php - - message: "#^Parameter \\#1 \\$component of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:buildAll\\(\\) expects array\\, array\\\\|null given\\.$#" + message: "#^Parameter \\#1 \\$component of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Lists\\\\ParameterDefinitions\\:\\:buildAll\\(\\) expects array\\, array\\\\|null given\\.$#" count: 1 path: src/Statements/CreateStatement.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 6de30b65..33ec6bcd 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -299,19 +299,29 @@ - - OrderKeyword[] - string - - - OrderKeyword[] - OrderKeyword[] - + + Expression::parse($parser, $list) + + + expr)]]> + expr)]]> + + + $options + + + + + name]]> + + + DataType::parse($parser, $list) + + + name)]]> + - $component - $list $options - $parser @@ -410,29 +420,16 @@ - - - + + $expr + - - name]]> - $inOut $name $type - DataType::parse($parser, $list) - - $state === 3 - - - name)]]> - - - $options - @@ -973,10 +970,6 @@ $partition - - array|null - public array|null $order = null; - @@ -1093,10 +1086,6 @@ join)]]> - - array|null - public array|null $order = null; - @@ -1135,10 +1124,6 @@ $set $where - - array|null - public array|null $order = null; - @@ -1632,18 +1617,6 @@ assertNotNull - - - - - - OrderKeyword - OrderKeyword - - expr->expr]]> diff --git a/src/Components/Lists/ParameterDefinitions.php b/src/Components/Lists/ParameterDefinitions.php new file mode 100644 index 00000000..46538be1 --- /dev/null +++ b/src/Components/Lists/ParameterDefinitions.php @@ -0,0 +1,111 @@ + $options parameters for parsing + * + * @return ParameterDefinition[] + */ + public static function parse(Parser $parser, TokensList $list, array $options = []): array + { + $ret = []; + + $expr = new ParameterDefinition(); + + /** + * The state of the parser. + * + * Below are the states of the parser. + * + * 0 -----------------------[ ( ]------------------------> 1 + * + * 1 ----------------[ IN / OUT / INOUT ]----------------> 1 + * 1 ----------------------[ name ]----------------------> 2 + * + * 2 -------------------[ data type ]--------------------> 3 + * + * 3 ------------------------[ , ]-----------------------> 1 + * 3 ------------------------[ ) ]-----------------------> (END) + */ + $state = 0; + + for (; $list->idx < $list->count; ++$list->idx) { + /** + * Token parsed at this moment. + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === TokenType::Delimiter) { + break; + } + + // Skipping whitespaces and comments. + if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { + continue; + } + + if ($state === 0) { + if (($token->type === TokenType::Operator) && ($token->value === '(')) { + $state = 1; + } + } elseif ($state === 1) { + if (($token->value === 'IN') || ($token->value === 'OUT') || ($token->value === 'INOUT')) { + $expr->inOut = $token->value; + ++$list->idx; + } elseif ($token->value === ')') { + ++$list->idx; + break; + } else { + $expr->name = $token->value; + $state = 2; + } + } elseif ($state === 2) { + $expr->type = DataType::parse($parser, $list); + $state = 3; + } elseif ($state === 3) { + $ret[] = $expr; + $expr = new ParameterDefinition(); + if ($token->value === ',') { + $state = 1; + } elseif ($token->value === ')') { + ++$list->idx; + break; + } + } + } + + // Last iteration was not saved. + if (isset($expr->name) && ($expr->name !== '')) { + $ret[] = $expr; + } + + --$list->idx; + + return $ret; + } + + /** @param ParameterDefinition[] $component the component to be built */ + public static function buildAll(array $component): string + { + return '(' . implode(', ', $component) . ')'; + } +} diff --git a/src/Components/ParameterDefinition.php b/src/Components/ParameterDefinition.php index a9069dd2..cbe30bb7 100644 --- a/src/Components/ParameterDefinition.php +++ b/src/Components/ParameterDefinition.php @@ -6,11 +6,7 @@ use PhpMyAdmin\SqlParser\Component; use PhpMyAdmin\SqlParser\Context; -use PhpMyAdmin\SqlParser\Parser; -use PhpMyAdmin\SqlParser\TokensList; -use PhpMyAdmin\SqlParser\TokenType; -use function implode; use function trim; /** @@ -51,92 +47,6 @@ public function __construct(string|null $name = null, string|null $inOut = null, $this->type = $type; } - /** - * @param Parser $parser the parser that serves as context - * @param TokensList $list the list of tokens that are being parsed - * @param array $options parameters for parsing - * - * @return ParameterDefinition[] - */ - public static function parse(Parser $parser, TokensList $list, array $options = []): array - { - $ret = []; - - $expr = new static(); - - /** - * The state of the parser. - * - * Below are the states of the parser. - * - * 0 -----------------------[ ( ]------------------------> 1 - * - * 1 ----------------[ IN / OUT / INOUT ]----------------> 1 - * 1 ----------------------[ name ]----------------------> 2 - * - * 2 -------------------[ data type ]--------------------> 3 - * - * 3 ------------------------[ , ]-----------------------> 1 - * 3 ------------------------[ ) ]-----------------------> (END) - */ - $state = 0; - - for (; $list->idx < $list->count; ++$list->idx) { - /** - * Token parsed at this moment. - */ - $token = $list->tokens[$list->idx]; - - // End of statement. - if ($token->type === TokenType::Delimiter) { - break; - } - - // Skipping whitespaces and comments. - if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { - continue; - } - - if ($state === 0) { - if (($token->type === TokenType::Operator) && ($token->value === '(')) { - $state = 1; - } - } elseif ($state === 1) { - if (($token->value === 'IN') || ($token->value === 'OUT') || ($token->value === 'INOUT')) { - $expr->inOut = $token->value; - ++$list->idx; - } elseif ($token->value === ')') { - ++$list->idx; - break; - } else { - $expr->name = $token->value; - $state = 2; - } - } elseif ($state === 2) { - $expr->type = DataType::parse($parser, $list); - $state = 3; - } elseif ($state === 3) { - $ret[] = $expr; - $expr = new static(); - if ($token->value === ',') { - $state = 1; - } elseif ($token->value === ')') { - ++$list->idx; - break; - } - } - } - - // Last iteration was not saved. - if (isset($expr->name) && ($expr->name !== '')) { - $ret[] = $expr; - } - - --$list->idx; - - return $ret; - } - public function build(): string { $tmp = ''; @@ -149,12 +59,6 @@ public function build(): string ); } - /** @param ParameterDefinition[] $component the component to be built */ - public static function buildAll(array $component): string - { - return '(' . implode(', ', $component) . ')'; - } - public function __toString(): string { return $this->build(); diff --git a/src/Statements/CreateStatement.php b/src/Statements/CreateStatement.php index a99c26c2..6c41c9b0 100644 --- a/src/Statements/CreateStatement.php +++ b/src/Statements/CreateStatement.php @@ -9,6 +9,7 @@ use PhpMyAdmin\SqlParser\Components\DataType; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\Lists\CreateDefinitions; +use PhpMyAdmin\SqlParser\Components\Lists\ParameterDefinitions; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\ParameterDefinition; use PhpMyAdmin\SqlParser\Components\PartitionDefinition; @@ -480,7 +481,7 @@ public function build(): string return 'CREATE ' . $this->options->build() . ' ' . $this->name->build() . ' ' - . ParameterDefinition::buildAll($this->parameters) . ' ' + . ParameterDefinitions::buildAll($this->parameters) . ' ' . $tmp . ' ' . $this->entityOptions->build() . ' ' . TokensList::buildFromArray($this->body); } @@ -666,7 +667,7 @@ public function parse(Parser $parser, TokensList $list): void } } } elseif ($this->options->has('PROCEDURE') || $this->options->has('FUNCTION')) { - $this->parameters = ParameterDefinition::parse($parser, $list); + $this->parameters = ParameterDefinitions::parse($parser, $list); if ($this->options->has('FUNCTION')) { $prevToken = $token; $token = $list->getNextOfType(TokenType::Keyword); diff --git a/src/Utils/Routine.php b/src/Utils/Routine.php index 60f9bd07..ae760147 100644 --- a/src/Utils/Routine.php +++ b/src/Utils/Routine.php @@ -5,7 +5,7 @@ namespace PhpMyAdmin\SqlParser\Utils; use PhpMyAdmin\SqlParser\Components\DataType; -use PhpMyAdmin\SqlParser\Components\ParameterDefinition; +use PhpMyAdmin\SqlParser\Components\Lists\ParameterDefinitions; use PhpMyAdmin\SqlParser\Lexer; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statements\CreateStatement; @@ -64,7 +64,7 @@ public static function getParameter(string $param): array $lexer = new Lexer('(' . $param . ')'); // A dummy parser is used for error reporting. - $param = ParameterDefinition::parse(new Parser(), $lexer->list); + $param = ParameterDefinitions::parse(new Parser(), $lexer->list); if ($param === []) { return [ diff --git a/tests/Builder/CreateStatementTest.php b/tests/Builder/CreateStatementTest.php index 942c9964..e18ec554 100644 --- a/tests/Builder/CreateStatementTest.php +++ b/tests/Builder/CreateStatementTest.php @@ -9,8 +9,8 @@ use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\Key; use PhpMyAdmin\SqlParser\Components\Lists\CreateDefinitions; +use PhpMyAdmin\SqlParser\Components\Lists\ParameterDefinitions; use PhpMyAdmin\SqlParser\Components\OptionsArray; -use PhpMyAdmin\SqlParser\Components\ParameterDefinition; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statements\CreateStatement; use PhpMyAdmin\SqlParser\Tests\TestCase; @@ -515,7 +515,7 @@ public function testBuilderCreateProcedure(): void $this->assertNotNull($stmt->parameters); $this->assertSame( '(IN `_var` INT)', - ParameterDefinition::buildAll($stmt->parameters), + ParameterDefinitions::buildAll($stmt->parameters), ); $this->assertSame( @@ -618,7 +618,7 @@ public function testBuilderCreateFunction(): void $this->assertNotNull($stmt->parameters); $this->assertSame( '(`p_inventory_id` INT)', - ParameterDefinition::buildAll($stmt->parameters), + ParameterDefinitions::buildAll($stmt->parameters), ); $this->assertSame( diff --git a/tests/Components/ParameterDefinitionTest.php b/tests/Components/ParameterDefinitionTest.php index c7309889..fbbe0101 100644 --- a/tests/Components/ParameterDefinitionTest.php +++ b/tests/Components/ParameterDefinitionTest.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\ParameterDefinition; +use PhpMyAdmin\SqlParser\Components\Lists\ParameterDefinitions; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Tests\TestCase; @@ -12,7 +12,7 @@ class ParameterDefinitionTest extends TestCase { public function testParse(): void { - $component = ParameterDefinition::parse( + $component = ParameterDefinitions::parse( new Parser(), $this->getTokensList('(a INT, b INT'), ); @@ -23,7 +23,7 @@ public function testParse(): void public function testParseComplex(): void { $parser = new Parser(); - $component = ParameterDefinition::parse( + $component = ParameterDefinitions::parse( $parser, $this->getTokensList('CREATE DEFINER=`root`@`%` PROCEDURE `foo`( $bar int )'), ); From abc722b2fc178b4ba68df2f29073c0fccae3ff4f Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 16:19:49 +0100 Subject: [PATCH 11/17] Split up RenameOperation Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 34 ++++-- psalm-baseline.xml | 51 ++++----- src/Components/Lists/RenameOperations.php | 130 ++++++++++++++++++++++ src/Components/RenameOperation.php | 116 ------------------- src/Parser.php | 2 +- src/Statements/RenameStatement.php | 3 +- tests/Components/RenameOperationTest.php | 6 +- 7 files changed, 184 insertions(+), 158 deletions(-) create mode 100644 src/Components/Lists/RenameOperations.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 025b4ef1..f87706a2 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -245,6 +245,26 @@ parameters: count: 1 path: src/Components/Lists/ParameterDefinitions.php + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$new \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" + count: 1 + path: src/Components/Lists/RenameOperations.php + + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$new \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" + count: 1 + path: src/Components/Lists/RenameOperations.php + + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$old \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" + count: 1 + path: src/Components/Lists/RenameOperations.php + + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$old \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" + count: 2 + path: src/Components/Lists/RenameOperations.php + - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\LockExpression\\:\\:\\$table \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 @@ -362,22 +382,12 @@ parameters: - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$new \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" - count: 2 - path: src/Components/RenameOperation.php - - - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$new \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" count: 1 path: src/Components/RenameOperation.php - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$old \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" - count: 2 - path: src/Components/RenameOperation.php - - - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$old \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" - count: 2 + count: 1 path: src/Components/RenameOperation.php - @@ -731,7 +741,7 @@ parameters: path: src/Statements/PurgeStatement.php - - message: "#^Parameter \\#1 \\$component of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:buildAll\\(\\) expects array\\, array\\\\|null given\\.$#" + message: "#^Parameter \\#1 \\$component of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Lists\\\\RenameOperations\\:\\:buildAll\\(\\) expects array\\, array\\\\|null given\\.$#" count: 1 path: src/Statements/RenameStatement.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 33ec6bcd..2d9c39f8 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -324,6 +324,32 @@ $options + + + true, + 'parseField' => 'table', + ], + )]]> + true, + 'parseField' => 'table', + ], + )]]> + + + old)]]> + + + $options + + $table @@ -498,32 +524,7 @@ $new $old - true, - 'parseField' => 'table', - ], - )]]> - true, - 'parseField' => 'table', - ], - )]]> - - $state === 3 - - - old)]]> - - - $options - diff --git a/src/Components/Lists/RenameOperations.php b/src/Components/Lists/RenameOperations.php new file mode 100644 index 00000000..f6027639 --- /dev/null +++ b/src/Components/Lists/RenameOperations.php @@ -0,0 +1,130 @@ + $options parameters for parsing + * + * @return RenameOperation[] + */ + public static function parse(Parser $parser, TokensList $list, array $options = []): array + { + $ret = []; + + $expr = new RenameOperation(); + + /** + * The state of the parser. + * + * Below are the states of the parser. + * + * 0 ---------------------[ old name ]--------------------> 1 + * + * 1 ------------------------[ TO ]-----------------------> 2 + * + * 2 ---------------------[ new name ]--------------------> 3 + * + * 3 ------------------------[ , ]------------------------> 0 + * 3 -----------------------[ else ]----------------------> (END) + */ + $state = 0; + + for (; $list->idx < $list->count; ++$list->idx) { + /** + * Token parsed at this moment. + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === TokenType::Delimiter) { + break; + } + + // Skipping whitespaces and comments. + if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { + continue; + } + + if ($state === 0) { + $expr->old = Expression::parse( + $parser, + $list, + [ + 'breakOnAlias' => true, + 'parseField' => 'table', + ], + ); + if (empty($expr->old)) { + $parser->error('The old name of the table was expected.', $token); + } + + $state = 1; + } elseif ($state === 1) { + if ($token->type !== TokenType::Keyword || $token->keyword !== 'TO') { + $parser->error('Keyword "TO" was expected.', $token); + break; + } + + $state = 2; + } elseif ($state === 2) { + $expr->new = Expression::parse( + $parser, + $list, + [ + 'breakOnAlias' => true, + 'parseField' => 'table', + ], + ); + if (empty($expr->new)) { + $parser->error('The new name of the table was expected.', $token); + } + + $state = 3; + } elseif ($state === 3) { + if (($token->type !== TokenType::Operator) || ($token->value !== ',')) { + break; + } + + $ret[] = $expr; + $expr = new RenameOperation(); + $state = 0; + } + } + + if ($state !== 3) { + $parser->error('A rename operation was expected.', $list->tokens[$list->idx - 1]); + } + + // Last iteration was not saved. + if (! empty($expr->old)) { + $ret[] = $expr; + } + + --$list->idx; + + return $ret; + } + + /** @param RenameOperation[] $component the component to be built */ + public static function buildAll(array $component): string + { + return implode(', ', $component); + } +} diff --git a/src/Components/RenameOperation.php b/src/Components/RenameOperation.php index 49e6ced9..ef111383 100644 --- a/src/Components/RenameOperation.php +++ b/src/Components/RenameOperation.php @@ -5,11 +5,6 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; -use PhpMyAdmin\SqlParser\Parser; -use PhpMyAdmin\SqlParser\TokensList; -use PhpMyAdmin\SqlParser\TokenType; - -use function implode; /** * `RENAME TABLE` keyword parser. @@ -40,122 +35,11 @@ public function __construct(Expression|null $old = null, Expression|null $new = $this->new = $new; } - /** - * @param Parser $parser the parser that serves as context - * @param TokensList $list the list of tokens that are being parsed - * @param array $options parameters for parsing - * - * @return RenameOperation[] - */ - public static function parse(Parser $parser, TokensList $list, array $options = []): array - { - $ret = []; - - $expr = new static(); - - /** - * The state of the parser. - * - * Below are the states of the parser. - * - * 0 ---------------------[ old name ]--------------------> 1 - * - * 1 ------------------------[ TO ]-----------------------> 2 - * - * 2 ---------------------[ new name ]--------------------> 3 - * - * 3 ------------------------[ , ]------------------------> 0 - * 3 -----------------------[ else ]----------------------> (END) - */ - $state = 0; - - for (; $list->idx < $list->count; ++$list->idx) { - /** - * Token parsed at this moment. - */ - $token = $list->tokens[$list->idx]; - - // End of statement. - if ($token->type === TokenType::Delimiter) { - break; - } - - // Skipping whitespaces and comments. - if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { - continue; - } - - if ($state === 0) { - $expr->old = Expression::parse( - $parser, - $list, - [ - 'breakOnAlias' => true, - 'parseField' => 'table', - ], - ); - if (empty($expr->old)) { - $parser->error('The old name of the table was expected.', $token); - } - - $state = 1; - } elseif ($state === 1) { - if ($token->type !== TokenType::Keyword || $token->keyword !== 'TO') { - $parser->error('Keyword "TO" was expected.', $token); - break; - } - - $state = 2; - } elseif ($state === 2) { - $expr->new = Expression::parse( - $parser, - $list, - [ - 'breakOnAlias' => true, - 'parseField' => 'table', - ], - ); - if (empty($expr->new)) { - $parser->error('The new name of the table was expected.', $token); - } - - $state = 3; - } elseif ($state === 3) { - if (($token->type !== TokenType::Operator) || ($token->value !== ',')) { - break; - } - - $ret[] = $expr; - $expr = new static(); - $state = 0; - } - } - - if ($state !== 3) { - $parser->error('A rename operation was expected.', $list->tokens[$list->idx - 1]); - } - - // Last iteration was not saved. - if (! empty($expr->old)) { - $ret[] = $expr; - } - - --$list->idx; - - return $ret; - } - public function build(): string { return $this->old . ' TO ' . $this->new; } - /** @param RenameOperation[] $component the component to be built */ - public static function buildAll(array $component): string - { - return implode(', ', $component); - } - public function __toString(): string { return $this->build(); diff --git a/src/Parser.php b/src/Parser.php index ba6a17cd..8863974d 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -298,7 +298,7 @@ class Parser 'field' => 'procedure', ], 'RENAME' => [ - 'class' => Components\RenameOperation::class, + 'class' => Components\Lists\RenameOperations::class, 'field' => 'renames', ], 'REPAIR' => [ diff --git a/src/Statements/RenameStatement.php b/src/Statements/RenameStatement.php index 3b83f83f..7cf06af7 100644 --- a/src/Statements/RenameStatement.php +++ b/src/Statements/RenameStatement.php @@ -4,6 +4,7 @@ namespace PhpMyAdmin\SqlParser\Statements; +use PhpMyAdmin\SqlParser\Components\Lists\RenameOperations; use PhpMyAdmin\SqlParser\Components\RenameOperation; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statement; @@ -47,6 +48,6 @@ public function before(Parser $parser, TokensList $list, Token $token): void public function build(): string { - return 'RENAME TABLE ' . RenameOperation::buildAll($this->renames); + return 'RENAME TABLE ' . RenameOperations::buildAll($this->renames); } } diff --git a/tests/Components/RenameOperationTest.php b/tests/Components/RenameOperationTest.php index 9298f35d..302e20a4 100644 --- a/tests/Components/RenameOperationTest.php +++ b/tests/Components/RenameOperationTest.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\RenameOperation; +use PhpMyAdmin\SqlParser\Components\Lists\RenameOperations; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Tests\TestCase; @@ -12,7 +12,7 @@ class RenameOperationTest extends TestCase { public function testBuildAll(): void { - $component = RenameOperation::parse(new Parser(), $this->getTokensList('a TO b, c TO d')); - $this->assertEquals(RenameOperation::buildAll($component), 'a TO b, c TO d'); + $component = RenameOperations::parse(new Parser(), $this->getTokensList('a TO b, c TO d')); + $this->assertEquals(RenameOperations::buildAll($component), 'a TO b, c TO d'); } } From 8ec04f2b662ff25c834def7c4f3de875b10305bc Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 16:22:40 +0100 Subject: [PATCH 12/17] Split up SetOperation Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 12 +-- psalm-baseline.xml | 23 +++-- src/Components/Lists/SetOperations.php | 121 +++++++++++++++++++++++++ src/Components/SetOperation.php | 110 ---------------------- src/Parser.php | 2 +- src/Statements/InsertStatement.php | 9 +- src/Statements/LoadStatement.php | 5 +- src/Statements/ReplaceStatement.php | 5 +- src/Statements/SetStatement.php | 3 +- 9 files changed, 152 insertions(+), 138 deletions(-) create mode 100644 src/Components/Lists/SetOperations.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index f87706a2..29b55e21 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -265,6 +265,11 @@ parameters: count: 2 path: src/Components/Lists/RenameOperations.php + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\SetOperation\\:\\:\\$value \\(string\\) does not accept string\\|null\\.$#" + count: 1 + path: src/Components/Lists/SetOperations.php + - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\LockExpression\\:\\:\\$table \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 @@ -390,11 +395,6 @@ parameters: count: 1 path: src/Components/RenameOperation.php - - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\SetOperation\\:\\:\\$value \\(string\\) does not accept string\\|null\\.$#" - count: 1 - path: src/Components/SetOperation.php - - message: "#^Static property PhpMyAdmin\\\\SqlParser\\\\Context\\:\\:\\$keywords \\(non\\-empty\\-array\\\\) does not accept default value of type array\\{\\}\\.$#" count: 1 @@ -751,7 +751,7 @@ parameters: path: src/Statements/SetStatement.php - - message: "#^Parameter \\#1 \\$component of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\SetOperation\\:\\:buildAll\\(\\) expects array\\, array\\\\|null given\\.$#" + message: "#^Parameter \\#1 \\$component of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Lists\\\\SetOperations\\:\\:buildAll\\(\\) expects array\\, array\\\\|null given\\.$#" count: 1 path: src/Statements/SetStatement.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 2d9c39f8..ee532918 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -350,6 +350,17 @@ $options + + + expr]]> + + + value === ',']]> + + + $options + + $table @@ -526,18 +537,6 @@ $old - - - expr]]> - - - $state === 1 - value === ',']]> - - - $options - - [] diff --git a/src/Components/Lists/SetOperations.php b/src/Components/Lists/SetOperations.php new file mode 100644 index 00000000..35eeb68d --- /dev/null +++ b/src/Components/Lists/SetOperations.php @@ -0,0 +1,121 @@ + $options parameters for parsing + * + * @return SetOperation[] + */ + public static function parse(Parser $parser, TokensList $list, array $options = []): array + { + $ret = []; + + $expr = new SetOperation(); + + /** + * The state of the parser. + * + * Below are the states of the parser. + * + * 0 ---------------------[ col_name ]--------------------> 0 + * 0 ---------------------[ = or := ]---------------------> 1 + * 1 -----------------------[ value ]---------------------> 1 + * 1 ------------------------[ , ]------------------------> 0 + */ + $state = 0; + + /** + * Token when the parser has seen the latest comma + */ + $commaLastSeenAt = null; + + for (; $list->idx < $list->count; ++$list->idx) { + /** + * Token parsed at this moment. + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === TokenType::Delimiter) { + break; + } + + // Skipping whitespaces and comments. + if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { + continue; + } + + // No keyword is expected. + if ( + ($token->type === TokenType::Keyword) + && ($token->flags & Token::FLAG_KEYWORD_RESERVED) + && ($state === 0) + ) { + break; + } + + if ($state === 0) { + if (in_array($token->token, ['=', ':='], true)) { + $state = 1; + } elseif ($token->value !== ',') { + $expr->column .= $token->token; + } elseif ($token->value === ',') { + $commaLastSeenAt = $token; + } + } elseif ($state === 1) { + $tmp = Expression::parse( + $parser, + $list, + ['breakOnAlias' => true], + ); + if ($tmp === null) { + $parser->error('Missing expression.', $token); + break; + } + + $expr->column = trim($expr->column); + $expr->value = $tmp->expr; + $ret[] = $expr; + $expr = new SetOperation(); + $state = 0; + $commaLastSeenAt = null; + } + } + + --$list->idx; + + // We saw a comma, but didn't see a column-value pair after it + if ($commaLastSeenAt !== null) { + $parser->error('Unexpected token.', $commaLastSeenAt); + } + + return $ret; + } + + /** @param SetOperation[] $component the component to be built */ + public static function buildAll(array $component): string + { + return implode(', ', $component); + } +} diff --git a/src/Components/SetOperation.php b/src/Components/SetOperation.php index 2379e116..58386aeb 100644 --- a/src/Components/SetOperation.php +++ b/src/Components/SetOperation.php @@ -5,18 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; -use PhpMyAdmin\SqlParser\Parser; -use PhpMyAdmin\SqlParser\Token; -use PhpMyAdmin\SqlParser\TokensList; -use PhpMyAdmin\SqlParser\TokenType; -use function implode; -use function in_array; -use function trim; - -/** - * `SET` keyword parser. - */ final class SetOperation implements Component { /** @@ -43,110 +32,11 @@ public function __construct(string $column = '', string $value = '') $this->value = $value; } - /** - * @param Parser $parser the parser that serves as context - * @param TokensList $list the list of tokens that are being parsed - * @param array $options parameters for parsing - * - * @return SetOperation[] - */ - public static function parse(Parser $parser, TokensList $list, array $options = []): array - { - $ret = []; - - $expr = new static(); - - /** - * The state of the parser. - * - * Below are the states of the parser. - * - * 0 ---------------------[ col_name ]--------------------> 0 - * 0 ---------------------[ = or := ]---------------------> 1 - * 1 -----------------------[ value ]---------------------> 1 - * 1 ------------------------[ , ]------------------------> 0 - */ - $state = 0; - - /** - * Token when the parser has seen the latest comma - */ - $commaLastSeenAt = null; - - for (; $list->idx < $list->count; ++$list->idx) { - /** - * Token parsed at this moment. - */ - $token = $list->tokens[$list->idx]; - - // End of statement. - if ($token->type === TokenType::Delimiter) { - break; - } - - // Skipping whitespaces and comments. - if (($token->type === TokenType::Whitespace) || ($token->type === TokenType::Comment)) { - continue; - } - - // No keyword is expected. - if ( - ($token->type === TokenType::Keyword) - && ($token->flags & Token::FLAG_KEYWORD_RESERVED) - && ($state === 0) - ) { - break; - } - - if ($state === 0) { - if (in_array($token->token, ['=', ':='], true)) { - $state = 1; - } elseif ($token->value !== ',') { - $expr->column .= $token->token; - } elseif ($token->value === ',') { - $commaLastSeenAt = $token; - } - } elseif ($state === 1) { - $tmp = Expression::parse( - $parser, - $list, - ['breakOnAlias' => true], - ); - if ($tmp === null) { - $parser->error('Missing expression.', $token); - break; - } - - $expr->column = trim($expr->column); - $expr->value = $tmp->expr; - $ret[] = $expr; - $expr = new static(); - $state = 0; - $commaLastSeenAt = null; - } - } - - --$list->idx; - - // We saw a comma, but didn't see a column-value pair after it - if ($commaLastSeenAt !== null) { - $parser->error('Unexpected token.', $commaLastSeenAt); - } - - return $ret; - } - public function build(): string { return $this->column . ' = ' . $this->value; } - /** @param SetOperation[] $component the component to be built */ - public static function buildAll(array $component): string - { - return implode(', ', $component); - } - public function __toString(): string { return $this->build(); diff --git a/src/Parser.php b/src/Parser.php index 8863974d..0a6bc3b1 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -312,7 +312,7 @@ class Parser 'options' => ['parseField' => 'table'], ], 'SET' => [ - 'class' => Components\SetOperation::class, + 'class' => Components\Lists\SetOperations::class, 'field' => 'set', ], 'SELECT' => [ diff --git a/src/Statements/InsertStatement.php b/src/Statements/InsertStatement.php index 5bcb51b3..91c2f4d0 100644 --- a/src/Statements/InsertStatement.php +++ b/src/Statements/InsertStatement.php @@ -7,6 +7,7 @@ use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Components\IntoKeyword; use PhpMyAdmin\SqlParser\Components\Lists\Array2d; +use PhpMyAdmin\SqlParser\Components\Lists\SetOperations; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\SetOperation; use PhpMyAdmin\SqlParser\Parser; @@ -113,13 +114,13 @@ public function build(): string if ($this->values !== null && $this->values !== []) { $ret .= ' VALUES ' . ArrayObj::buildAll($this->values); } elseif ($this->set !== null && $this->set !== []) { - $ret .= ' SET ' . SetOperation::buildAll($this->set); + $ret .= ' SET ' . SetOperations::buildAll($this->set); } elseif ($this->select !== null && strlen((string) $this->select) > 0) { $ret .= ' ' . $this->select->build(); } if ($this->onDuplicateSet !== null && $this->onDuplicateSet !== []) { - $ret .= ' ON DUPLICATE KEY UPDATE ' . SetOperation::buildAll($this->onDuplicateSet); + $ret .= ' ON DUPLICATE KEY UPDATE ' . SetOperations::buildAll($this->onDuplicateSet); } return $ret; @@ -199,7 +200,7 @@ public function parse(Parser $parser, TokensList $list): void } elseif ($token->keyword === 'SET') { ++$list->idx; // skip SET - $this->set = SetOperation::parse($parser, $list); + $this->set = SetOperations::parse($parser, $list); } elseif ($token->keyword === 'SELECT') { $this->select = new SelectStatement($parser, $list); } elseif ($token->keyword === 'WITH') { @@ -231,7 +232,7 @@ public function parse(Parser $parser, TokensList $list): void if ($miniState === 5) { ++$list->idx; - $this->onDuplicateSet = SetOperation::parse($parser, $list); + $this->onDuplicateSet = SetOperations::parse($parser, $list); $state = 3; } } diff --git a/src/Statements/LoadStatement.php b/src/Statements/LoadStatement.php index 11d0129a..41bd3a97 100644 --- a/src/Statements/LoadStatement.php +++ b/src/Statements/LoadStatement.php @@ -7,6 +7,7 @@ use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; +use PhpMyAdmin\SqlParser\Components\Lists\SetOperations; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\SetOperation; use PhpMyAdmin\SqlParser\Parser; @@ -189,7 +190,7 @@ public function build(): string } if ($this->set !== null && $this->set !== []) { - $ret .= ' SET ' . SetOperation::buildAll($this->set); + $ret .= ' SET ' . SetOperations::buildAll($this->set); } return $ret; @@ -357,7 +358,7 @@ public function parseKeywordsAccordingToState(Parser $parser, TokensList $list, case 7: if ($token->keyword === 'SET') { ++$list->idx; - $this->set = SetOperation::parse($parser, $list); + $this->set = SetOperations::parse($parser, $list); return 8; } diff --git a/src/Statements/ReplaceStatement.php b/src/Statements/ReplaceStatement.php index cad7515c..3cb53be5 100644 --- a/src/Statements/ReplaceStatement.php +++ b/src/Statements/ReplaceStatement.php @@ -7,6 +7,7 @@ use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Components\IntoKeyword; use PhpMyAdmin\SqlParser\Components\Lists\Array2d; +use PhpMyAdmin\SqlParser\Components\Lists\SetOperations; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\SetOperation; use PhpMyAdmin\SqlParser\Parser; @@ -85,7 +86,7 @@ public function build(): string if ($this->values !== null && $this->values !== []) { $ret .= ' VALUES ' . ArrayObj::buildAll($this->values); } elseif ($this->set !== null && $this->set !== []) { - $ret .= ' SET ' . SetOperation::buildAll($this->set); + $ret .= ' SET ' . SetOperations::buildAll($this->set); } elseif ($this->select !== null && strlen((string) $this->select) > 0) { $ret .= ' ' . $this->select->build(); } @@ -160,7 +161,7 @@ public function parse(Parser $parser, TokensList $list): void } elseif ($token->keyword === 'SET') { ++$list->idx; // skip SET - $this->set = SetOperation::parse($parser, $list); + $this->set = SetOperations::parse($parser, $list); } elseif ($token->keyword === 'SELECT') { $this->select = new SelectStatement($parser, $list); } else { diff --git a/src/Statements/SetStatement.php b/src/Statements/SetStatement.php index 4a7c12a3..9603a890 100644 --- a/src/Statements/SetStatement.php +++ b/src/Statements/SetStatement.php @@ -4,6 +4,7 @@ namespace PhpMyAdmin\SqlParser\Statements; +use PhpMyAdmin\SqlParser\Components\Lists\SetOperations; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\SetOperation; use PhpMyAdmin\SqlParser\Statement; @@ -96,7 +97,7 @@ class SetStatement extends Statement public function build(): string { $ret = 'SET ' . $this->options->build() - . ' ' . SetOperation::buildAll($this->set) + . ' ' . SetOperations::buildAll($this->set) . ' ' . ($this->endOptions?->build() ?? ''); return trim($ret); From 9f4b28c696c20555d88cf46d163753dbf2ce786b Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 17:04:57 +0100 Subject: [PATCH 13/17] Add Parseable interface Signed-off-by: Kamil Tekiela --- psalm-baseline.xml | 21 ------------------ src/Components/AlterOperation.php | 3 ++- src/Components/ArrayObj.php | 3 ++- src/Components/CaseExpression.php | 3 ++- src/Components/DataType.php | 3 ++- src/Components/Expression.php | 3 ++- src/Components/FunctionCall.php | 3 ++- src/Components/IntoKeyword.php | 3 ++- src/Components/Key.php | 3 ++- src/Components/Limit.php | 3 ++- src/Components/Lists/Array2d.php | 3 ++- src/Components/Lists/Conditions.php | 3 ++- src/Components/Lists/CreateDefinitions.php | 3 ++- src/Components/Lists/ExpressionArray.php | 3 ++- src/Components/Lists/GroupKeywords.php | 3 ++- src/Components/Lists/IndexHints.php | 3 ++- src/Components/Lists/JoinKeywords.php | 3 ++- src/Components/Lists/OrderKeywords.php | 3 ++- src/Components/Lists/ParameterDefinitions.php | 3 ++- src/Components/Lists/RenameOperations.php | 3 ++- src/Components/Lists/SetOperations.php | 3 ++- src/Components/LockExpression.php | 3 ++- src/Components/OptionsArray.php | 3 ++- src/Components/PartitionDefinition.php | 3 ++- src/Components/Reference.php | 3 ++- src/Components/UnionKeyword.php | 5 +++-- src/Parseable.php | 22 +++++++++++++++++++ 27 files changed, 73 insertions(+), 47 deletions(-) create mode 100644 src/Parseable.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index ee532918..8957518e 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -77,9 +77,6 @@ alias)]]> alias)]]> - - $options - @@ -265,9 +262,6 @@ expr)]]> expr)]]> - - $options - @@ -289,9 +283,6 @@ keyword])]]> keyword])]]> - - $options - $state $state @@ -306,9 +297,6 @@ expr)]]> expr)]]> - - $options - @@ -320,9 +308,6 @@ name)]]> - - $options - @@ -346,9 +331,6 @@ old)]]> - - $options - @@ -357,9 +339,6 @@ value === ',']]> - - $options - diff --git a/src/Components/AlterOperation.php b/src/Components/AlterOperation.php index b540550e..af89ce81 100644 --- a/src/Components/AlterOperation.php +++ b/src/Components/AlterOperation.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; @@ -19,7 +20,7 @@ /** * Parses an alter operation. */ -final class AlterOperation implements Component +final class AlterOperation implements Component, Parseable { /** * All database options. diff --git a/src/Components/ArrayObj.php b/src/Components/ArrayObj.php index 8ed4decb..e07277e8 100644 --- a/src/Components/ArrayObj.php +++ b/src/Components/ArrayObj.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -16,7 +17,7 @@ /** * Parses an array. */ -final class ArrayObj implements Component +final class ArrayObj implements Component, Parseable { /** * The array that contains the unprocessed value of each token. diff --git a/src/Components/CaseExpression.php b/src/Components/CaseExpression.php index af8633ee..60ff6236 100644 --- a/src/Components/CaseExpression.php +++ b/src/Components/CaseExpression.php @@ -7,6 +7,7 @@ use PhpMyAdmin\SqlParser\Component; use PhpMyAdmin\SqlParser\Components\Lists\Conditions; use PhpMyAdmin\SqlParser\Context; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; @@ -17,7 +18,7 @@ /** * Parses a reference to a CASE expression. */ -final class CaseExpression implements Component +final class CaseExpression implements Component, Parseable { /** * The value to be compared. diff --git a/src/Components/DataType.php b/src/Components/DataType.php index 4aecb8ac..8a96427b 100644 --- a/src/Components/DataType.php +++ b/src/Components/DataType.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; @@ -18,7 +19,7 @@ /** * Parses a data type. */ -final class DataType implements Component +final class DataType implements Component, Parseable { /** * All data type options. diff --git a/src/Components/Expression.php b/src/Components/Expression.php index 38a7558d..4b719718 100644 --- a/src/Components/Expression.php +++ b/src/Components/Expression.php @@ -8,6 +8,7 @@ use PhpMyAdmin\SqlParser\Component; use PhpMyAdmin\SqlParser\Context; use PhpMyAdmin\SqlParser\Exceptions\ParserException; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; @@ -24,7 +25,7 @@ * call, mathematical expression, etc.). */ #[AllowDynamicProperties] -final class Expression implements Component +final class Expression implements Component, Parseable { /** * List of allowed reserved keywords in expressions. diff --git a/src/Components/FunctionCall.php b/src/Components/FunctionCall.php index 0f307b2a..279fc8c7 100644 --- a/src/Components/FunctionCall.php +++ b/src/Components/FunctionCall.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -14,7 +15,7 @@ /** * Parses a function call. */ -final class FunctionCall implements Component +final class FunctionCall implements Component, Parseable { /** * The name of this function. diff --git a/src/Components/IntoKeyword.php b/src/Components/IntoKeyword.php index faedc4f6..3b828d16 100644 --- a/src/Components/IntoKeyword.php +++ b/src/Components/IntoKeyword.php @@ -6,6 +6,7 @@ use PhpMyAdmin\SqlParser\Component; use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; @@ -17,7 +18,7 @@ /** * `INTO` keyword parser. */ -final class IntoKeyword implements Component +final class IntoKeyword implements Component, Parseable { /** * FIELDS/COLUMNS Options for `SELECT...INTO` statements. diff --git a/src/Components/Key.php b/src/Components/Key.php index d6785b36..2524cfd5 100644 --- a/src/Components/Key.php +++ b/src/Components/Key.php @@ -6,6 +6,7 @@ use PhpMyAdmin\SqlParser\Component; use PhpMyAdmin\SqlParser\Context; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -18,7 +19,7 @@ * * Used for parsing `CREATE TABLE` statement. */ -final class Key implements Component +final class Key implements Component, Parseable { /** * All key options. diff --git a/src/Components/Limit.php b/src/Components/Limit.php index 784c293c..817c37e7 100644 --- a/src/Components/Limit.php +++ b/src/Components/Limit.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; @@ -13,7 +14,7 @@ /** * `LIMIT` keyword parser. */ -final class Limit implements Component +final class Limit implements Component, Parseable { /** * The number of rows skipped. diff --git a/src/Components/Lists/Array2d.php b/src/Components/Lists/Array2d.php index 57421e03..8258cb30 100644 --- a/src/Components/Lists/Array2d.php +++ b/src/Components/Lists/Array2d.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components\Lists; use PhpMyAdmin\SqlParser\Components\ArrayObj; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; @@ -17,7 +18,7 @@ /** * `VALUES` keyword parser. */ -final class Array2d +final class Array2d implements Parseable { /** * @param Parser $parser the parser that serves as context diff --git a/src/Components/Lists/Conditions.php b/src/Components/Lists/Conditions.php index bcea33d0..fc6c9178 100644 --- a/src/Components/Lists/Conditions.php +++ b/src/Components/Lists/Conditions.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components\Lists; use PhpMyAdmin\SqlParser\Components\Condition; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; @@ -17,7 +18,7 @@ /** * `WHERE` keyword parser. */ -final class Conditions +final class Conditions implements Parseable { /** * Logical operators that can be used to delimit expressions. diff --git a/src/Components/Lists/CreateDefinitions.php b/src/Components/Lists/CreateDefinitions.php index a3c90ac7..abcf4113 100644 --- a/src/Components/Lists/CreateDefinitions.php +++ b/src/Components/Lists/CreateDefinitions.php @@ -9,6 +9,7 @@ use PhpMyAdmin\SqlParser\Components\Key; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\Reference; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; @@ -21,7 +22,7 @@ * * Used for parsing `CREATE TABLE` statement. */ -final class CreateDefinitions +final class CreateDefinitions implements Parseable { /** * All field options. diff --git a/src/Components/Lists/ExpressionArray.php b/src/Components/Lists/ExpressionArray.php index 962f74a3..8c03710b 100644 --- a/src/Components/Lists/ExpressionArray.php +++ b/src/Components/Lists/ExpressionArray.php @@ -7,6 +7,7 @@ use PhpMyAdmin\SqlParser\Components\CaseExpression; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Exceptions\ParserException; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; @@ -21,7 +22,7 @@ /** * Parses a list of expressions delimited by a comma. */ -final class ExpressionArray +final class ExpressionArray implements Parseable { /** * @param Parser $parser the parser that serves as context diff --git a/src/Components/Lists/GroupKeywords.php b/src/Components/Lists/GroupKeywords.php index f5872b33..5e6bffcf 100644 --- a/src/Components/Lists/GroupKeywords.php +++ b/src/Components/Lists/GroupKeywords.php @@ -6,6 +6,7 @@ use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\GroupKeyword; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -15,7 +16,7 @@ /** * `GROUP BY` keyword parser. */ -final class GroupKeywords +final class GroupKeywords implements Parseable { /** * @param Parser $parser the parser that serves as context diff --git a/src/Components/Lists/IndexHints.php b/src/Components/Lists/IndexHints.php index 11a1d66e..c6b1f084 100644 --- a/src/Components/Lists/IndexHints.php +++ b/src/Components/Lists/IndexHints.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components\Lists; use PhpMyAdmin\SqlParser\Components\IndexHint; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -14,7 +15,7 @@ /** * Parses an Index hint. */ -final class IndexHints +final class IndexHints implements Parseable { /** * @param Parser $parser the parser that serves as context diff --git a/src/Components/Lists/JoinKeywords.php b/src/Components/Lists/JoinKeywords.php index 834181b9..c5d6d21c 100644 --- a/src/Components/Lists/JoinKeywords.php +++ b/src/Components/Lists/JoinKeywords.php @@ -7,6 +7,7 @@ use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\JoinKeyword; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -16,7 +17,7 @@ /** * `JOIN` keyword parser. */ -final class JoinKeywords +final class JoinKeywords implements Parseable { /** * @param Parser $parser the parser that serves as context diff --git a/src/Components/Lists/OrderKeywords.php b/src/Components/Lists/OrderKeywords.php index 7f862920..fcb8571c 100644 --- a/src/Components/Lists/OrderKeywords.php +++ b/src/Components/Lists/OrderKeywords.php @@ -6,6 +6,7 @@ use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\OrderKeyword; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -15,7 +16,7 @@ /** * `ORDER BY` keyword parser. */ -final class OrderKeywords +final class OrderKeywords implements Parseable { /** * @param Parser $parser the parser that serves as context diff --git a/src/Components/Lists/ParameterDefinitions.php b/src/Components/Lists/ParameterDefinitions.php index 46538be1..2ec2ec3f 100644 --- a/src/Components/Lists/ParameterDefinitions.php +++ b/src/Components/Lists/ParameterDefinitions.php @@ -6,6 +6,7 @@ use PhpMyAdmin\SqlParser\Components\DataType; use PhpMyAdmin\SqlParser\Components\ParameterDefinition; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -15,7 +16,7 @@ /** * The definition of a parameter of a function or procedure. */ -final class ParameterDefinitions +final class ParameterDefinitions implements Parseable { /** * @param Parser $parser the parser that serves as context diff --git a/src/Components/Lists/RenameOperations.php b/src/Components/Lists/RenameOperations.php index f6027639..058f1a38 100644 --- a/src/Components/Lists/RenameOperations.php +++ b/src/Components/Lists/RenameOperations.php @@ -6,6 +6,7 @@ use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\RenameOperation; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -15,7 +16,7 @@ /** * `RENAME TABLE` keyword parser. */ -final class RenameOperations +final class RenameOperations implements Parseable { /** * @param Parser $parser the parser that serves as context diff --git a/src/Components/Lists/SetOperations.php b/src/Components/Lists/SetOperations.php index 35eeb68d..4ea3a71e 100644 --- a/src/Components/Lists/SetOperations.php +++ b/src/Components/Lists/SetOperations.php @@ -6,6 +6,7 @@ use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\SetOperation; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; @@ -18,7 +19,7 @@ /** * `SET` keyword parser. */ -final class SetOperations +final class SetOperations implements Parseable { /** * @param Parser $parser the parser that serves as context diff --git a/src/Components/LockExpression.php b/src/Components/LockExpression.php index bc293d01..51397fbe 100644 --- a/src/Components/LockExpression.php +++ b/src/Components/LockExpression.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -14,7 +15,7 @@ /** * Parses a reference to a LOCK expression. */ -final class LockExpression implements Component +final class LockExpression implements Component, Parseable { /** * The table to be locked. diff --git a/src/Components/OptionsArray.php b/src/Components/OptionsArray.php index bd7fab74..371c56e5 100644 --- a/src/Components/OptionsArray.php +++ b/src/Components/OptionsArray.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -22,7 +23,7 @@ /** * Parses a list of options. */ -final class OptionsArray implements Component +final class OptionsArray implements Component, Parseable { /** * @param array $options The array of options. Options that have a value diff --git a/src/Components/PartitionDefinition.php b/src/Components/PartitionDefinition.php index de4e926f..6559f037 100644 --- a/src/Components/PartitionDefinition.php +++ b/src/Components/PartitionDefinition.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -17,7 +18,7 @@ * * Used for parsing `CREATE TABLE` statement. */ -final class PartitionDefinition implements Component +final class PartitionDefinition implements Component, Parseable { /** * All field options. diff --git a/src/Components/Reference.php b/src/Components/Reference.php index cc94c9e6..5d334eb2 100644 --- a/src/Components/Reference.php +++ b/src/Components/Reference.php @@ -6,6 +6,7 @@ use PhpMyAdmin\SqlParser\Component; use PhpMyAdmin\SqlParser\Context; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\TokenType; @@ -16,7 +17,7 @@ /** * `REFERENCES` keyword parser. */ -final class Reference implements Component +final class Reference implements Component, Parseable { /** * All references options. diff --git a/src/Components/UnionKeyword.php b/src/Components/UnionKeyword.php index 3829abf4..11f81707 100644 --- a/src/Components/UnionKeyword.php +++ b/src/Components/UnionKeyword.php @@ -5,6 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; +use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\Translator; @@ -15,7 +16,7 @@ /** * `UNION` keyword builder. */ -final class UnionKeyword implements Component +final class UnionKeyword implements Component, Parseable { /** * Parses the tokens contained in the given list in the context of the given parser. @@ -26,7 +27,7 @@ final class UnionKeyword implements Component * * @throws RuntimeException not implemented yet. */ - public static function parse(Parser $parser, TokensList $list, array $options = []): mixed + public static function parse(Parser $parser, TokensList $list, array $options = []): never { throw new RuntimeException(Translator::gettext('Not implemented yet.')); } diff --git a/src/Parseable.php b/src/Parseable.php new file mode 100644 index 00000000..b42ebca0 --- /dev/null +++ b/src/Parseable.php @@ -0,0 +1,22 @@ + $options parameters for parsing + * + * @return Component|Component[]|null + */ + public static function parse(Parser $parser, TokensList $list, array $options = []): Component|array|null; +} From 6e1dc5eff94cc5649d26dec6a17acf8dfd47c108 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 18:03:32 +0100 Subject: [PATCH 14/17] Rename Lists to Parsers Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 170 ++++++------- psalm-baseline.xml | 226 +++++++++--------- src/Components/CaseExpression.php | 2 +- src/Components/IntoKeyword.php | 2 +- src/Components/JoinKeyword.php | 2 +- src/Components/{Lists => Parsers}/Array2d.php | 2 +- .../{Lists => Parsers}/Conditions.php | 2 +- .../{Lists => Parsers}/CreateDefinitions.php | 2 +- .../{Lists => Parsers}/ExpressionArray.php | 2 +- .../{Lists => Parsers}/GroupKeywords.php | 2 +- .../{Lists => Parsers}/IndexHints.php | 2 +- .../{Lists => Parsers}/JoinKeywords.php | 2 +- .../{Lists => Parsers}/OrderKeywords.php | 2 +- .../ParameterDefinitions.php | 2 +- .../{Lists => Parsers}/RenameOperations.php | 2 +- .../{Lists => Parsers}/SetOperations.php | 2 +- src/Parser.php | 74 +++--- src/Statements/CreateStatement.php | 4 +- src/Statements/DeleteStatement.php | 8 +- src/Statements/InsertStatement.php | 4 +- src/Statements/LoadStatement.php | 4 +- src/Statements/RenameStatement.php | 2 +- src/Statements/ReplaceStatement.php | 4 +- src/Statements/SetStatement.php | 2 +- src/Statements/WithStatement.php | 2 +- src/Utils/Routine.php | 2 +- tests/Builder/CreateStatementTest.php | 4 +- tests/Components/Array2dTest.php | 2 +- tests/Components/ConditionTest.php | 2 +- tests/Components/CreateDefinitionTest.php | 2 +- tests/Components/ExpressionArrayTest.php | 2 +- tests/Components/GroupKeywordTest.php | 2 +- tests/Components/JoinKeywordTest.php | 2 +- tests/Components/OrderKeywordTest.php | 2 +- tests/Components/ParameterDefinitionTest.php | 2 +- tests/Components/RenameOperationTest.php | 2 +- 36 files changed, 276 insertions(+), 276 deletions(-) rename src/Components/{Lists => Parsers}/Array2d.php (98%) rename src/Components/{Lists => Parsers}/Conditions.php (99%) rename src/Components/{Lists => Parsers}/CreateDefinitions.php (99%) rename src/Components/{Lists => Parsers}/ExpressionArray.php (98%) rename src/Components/{Lists => Parsers}/GroupKeywords.php (98%) rename src/Components/{Lists => Parsers}/IndexHints.php (98%) rename src/Components/{Lists => Parsers}/JoinKeywords.php (98%) rename src/Components/{Lists => Parsers}/OrderKeywords.php (98%) rename src/Components/{Lists => Parsers}/ParameterDefinitions.php (98%) rename src/Components/{Lists => Parsers}/RenameOperations.php (98%) rename src/Components/{Lists => Parsers}/SetOperations.php (98%) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 29b55e21..95f776f5 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -171,179 +171,179 @@ parameters: path: src/Components/Limit.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\CreateDefinition\\:\\:\\$name \\(string\\|null\\) does not accept mixed\\.$#" - count: 2 - path: src/Components/Lists/CreateDefinitions.php - - - - message: "#^Method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Lists\\\\ExpressionArray\\:\\:parse\\(\\) should return array\\ but returns array\\, PhpMyAdmin\\\\SqlParser\\\\Components\\\\CaseExpression\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\>\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\LockExpression\\:\\:\\$table \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 - path: src/Components/Lists/ExpressionArray.php + path: src/Components/LockExpression.php - - message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|null given\\.$#" + message: "#^Cannot access offset 'equals' on mixed\\.$#" count: 1 - path: src/Components/Lists/ExpressionArray.php + path: src/Components/OptionsArray.php - - message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|null given\\.$#" - count: 1 - path: src/Components/Lists/ExpressionArray.php + message: "#^Cannot access offset 'expr' on mixed\\.$#" + count: 2 + path: src/Components/OptionsArray.php - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#" + message: "#^Cannot access offset 'name' on mixed\\.$#" count: 1 - path: src/Components/Lists/ExpressionArray.php + path: src/Components/OptionsArray.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\GroupKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" - count: 1 - path: src/Components/Lists/GroupKeywords.php + message: "#^Cannot access offset 'value' on mixed\\.$#" + count: 2 + path: src/Components/OptionsArray.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\GroupKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" + message: "#^Cannot access offset 1 on mixed\\.$#" count: 2 - path: src/Components/Lists/GroupKeywords.php + path: src/Components/OptionsArray.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\IndexHint\\:\\:\\$type \\(string\\|null\\) does not accept mixed\\.$#" + message: "#^Cannot access offset 2 on mixed\\.$#" count: 1 - path: src/Components/Lists/IndexHints.php + path: src/Components/OptionsArray.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\JoinKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" - count: 1 - path: src/Components/Lists/JoinKeywords.php + message: "#^Parameter \\#2 \\$string2 of function strcasecmp expects string, mixed given\\.$#" + count: 2 + path: src/Components/OptionsArray.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\JoinKeyword\\:\\:\\$using \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\) does not accept array\\\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\.$#" + message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#" count: 1 - path: src/Components/Lists/JoinKeywords.php + path: src/Components/OptionsArray.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\OrderKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" + message: "#^Parameter \\#3 \\$options of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\:\\:parse\\(\\) expects array\\, mixed given\\.$#" count: 1 - path: src/Components/Lists/OrderKeywords.php + path: src/Components/OptionsArray.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\OrderKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" - count: 2 - path: src/Components/Lists/OrderKeywords.php + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\OptionsArray\\:\\:\\$options \\(array\\\\) does not accept array\\\\.$#" + count: 8 + path: src/Components/OptionsArray.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$name \\(string\\) does not accept mixed\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\OrderKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 - path: src/Components/Lists/ParameterDefinitions.php + path: src/Components/OrderKeyword.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$name \\(string\\) in isset\\(\\) is not nullable\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$inOut \\(string\\) does not accept string\\|null\\.$#" count: 1 - path: src/Components/Lists/ParameterDefinitions.php + path: src/Components/ParameterDefinition.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$type \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\DataType\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\DataType\\|null\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$name \\(string\\) does not accept string\\|null\\.$#" count: 1 - path: src/Components/Lists/ParameterDefinitions.php + path: src/Components/ParameterDefinition.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$new \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$type \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\DataType\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\DataType\\|null\\.$#" count: 1 - path: src/Components/Lists/RenameOperations.php + path: src/Components/ParameterDefinition.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$new \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" - count: 1 - path: src/Components/Lists/RenameOperations.php + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\CreateDefinition\\:\\:\\$name \\(string\\|null\\) does not accept mixed\\.$#" + count: 2 + path: src/Components/Parsers/CreateDefinitions.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$old \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" + message: "#^Method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Parsers\\\\ExpressionArray\\:\\:parse\\(\\) should return array\\ but returns array\\, PhpMyAdmin\\\\SqlParser\\\\Components\\\\CaseExpression\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\>\\.$#" count: 1 - path: src/Components/Lists/RenameOperations.php + path: src/Components/Parsers/ExpressionArray.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$old \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" - count: 2 - path: src/Components/Lists/RenameOperations.php + message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|null given\\.$#" + count: 1 + path: src/Components/Parsers/ExpressionArray.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\SetOperation\\:\\:\\$value \\(string\\) does not accept string\\|null\\.$#" + message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|null given\\.$#" count: 1 - path: src/Components/Lists/SetOperations.php + path: src/Components/Parsers/ExpressionArray.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\LockExpression\\:\\:\\$table \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" + message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#" count: 1 - path: src/Components/LockExpression.php + path: src/Components/Parsers/ExpressionArray.php - - message: "#^Cannot access offset 'equals' on mixed\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\GroupKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 - path: src/Components/OptionsArray.php + path: src/Components/Parsers/GroupKeywords.php - - message: "#^Cannot access offset 'expr' on mixed\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\GroupKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" count: 2 - path: src/Components/OptionsArray.php + path: src/Components/Parsers/GroupKeywords.php - - message: "#^Cannot access offset 'name' on mixed\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\IndexHint\\:\\:\\$type \\(string\\|null\\) does not accept mixed\\.$#" count: 1 - path: src/Components/OptionsArray.php + path: src/Components/Parsers/IndexHints.php - - message: "#^Cannot access offset 'value' on mixed\\.$#" - count: 2 - path: src/Components/OptionsArray.php + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\JoinKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" + count: 1 + path: src/Components/Parsers/JoinKeywords.php - - message: "#^Cannot access offset 1 on mixed\\.$#" - count: 2 - path: src/Components/OptionsArray.php + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\JoinKeyword\\:\\:\\$using \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\) does not accept array\\\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\.$#" + count: 1 + path: src/Components/Parsers/JoinKeywords.php - - message: "#^Cannot access offset 2 on mixed\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\OrderKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 - path: src/Components/OptionsArray.php + path: src/Components/Parsers/OrderKeywords.php - - message: "#^Parameter \\#2 \\$string2 of function strcasecmp expects string, mixed given\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\OrderKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" count: 2 - path: src/Components/OptionsArray.php + path: src/Components/Parsers/OrderKeywords.php - - message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$name \\(string\\) does not accept mixed\\.$#" count: 1 - path: src/Components/OptionsArray.php + path: src/Components/Parsers/ParameterDefinitions.php - - message: "#^Parameter \\#3 \\$options of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\:\\:parse\\(\\) expects array\\, mixed given\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$name \\(string\\) in isset\\(\\) is not nullable\\.$#" count: 1 - path: src/Components/OptionsArray.php + path: src/Components/Parsers/ParameterDefinitions.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\OptionsArray\\:\\:\\$options \\(array\\\\) does not accept array\\\\.$#" - count: 8 - path: src/Components/OptionsArray.php + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$type \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\DataType\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\DataType\\|null\\.$#" + count: 1 + path: src/Components/Parsers/ParameterDefinitions.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\OrderKeyword\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$new \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 - path: src/Components/OrderKeyword.php + path: src/Components/Parsers/RenameOperations.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$inOut \\(string\\) does not accept string\\|null\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$new \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" count: 1 - path: src/Components/ParameterDefinition.php + path: src/Components/Parsers/RenameOperations.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$name \\(string\\) does not accept string\\|null\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$old \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" count: 1 - path: src/Components/ParameterDefinition.php + path: src/Components/Parsers/RenameOperations.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\ParameterDefinition\\:\\:\\$type \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\DataType\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\DataType\\|null\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\RenameOperation\\:\\:\\$old \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\) in empty\\(\\) is not falsy\\.$#" + count: 2 + path: src/Components/Parsers/RenameOperations.php + + - + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\SetOperation\\:\\:\\$value \\(string\\) does not accept string\\|null\\.$#" count: 1 - path: src/Components/ParameterDefinition.php + path: src/Components/Parsers/SetOperations.php - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\PartitionDefinition\\:\\:\\$expr \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|string\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|null\\.$#" @@ -626,7 +626,7 @@ parameters: path: src/Statements/CreateStatement.php - - message: "#^Parameter \\#1 \\$component of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Lists\\\\ParameterDefinitions\\:\\:buildAll\\(\\) expects array\\, array\\\\|null given\\.$#" + message: "#^Parameter \\#1 \\$component of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Parsers\\\\ParameterDefinitions\\:\\:buildAll\\(\\) expects array\\, array\\\\|null given\\.$#" count: 1 path: src/Statements/CreateStatement.php @@ -741,7 +741,7 @@ parameters: path: src/Statements/PurgeStatement.php - - message: "#^Parameter \\#1 \\$component of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Lists\\\\RenameOperations\\:\\:buildAll\\(\\) expects array\\, array\\\\|null given\\.$#" + message: "#^Parameter \\#1 \\$component of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Parsers\\\\RenameOperations\\:\\:buildAll\\(\\) expects array\\, array\\\\|null given\\.$#" count: 1 path: src/Statements/RenameStatement.php @@ -751,7 +751,7 @@ parameters: path: src/Statements/SetStatement.php - - message: "#^Parameter \\#1 \\$component of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Lists\\\\SetOperations\\:\\:buildAll\\(\\) expects array\\, array\\\\|null given\\.$#" + message: "#^Parameter \\#1 \\$component of static method PhpMyAdmin\\\\SqlParser\\\\Components\\\\Parsers\\\\SetOperations\\:\\:buildAll\\(\\) expects array\\, array\\\\|null given\\.$#" count: 1 path: src/Statements/SetStatement.php diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 8957518e..92bcf53a 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -227,119 +227,6 @@ rowCount]]> - - - $state === 1 - - - - - name]]> - name]]> - - - - - $ret - - - Expression[] - - - $expr - $expr - $expr - - - $state === 1 - - - - - Expression::parse($parser, $list) - - - expr)]]> - expr)]]> - - - - - type]]> - - - - - keyword]]]> - keyword]]]> - - - ArrayObj::parse($parser, $list) - - - 'table'])]]> - - - keyword])]]> - keyword])]]> - - - $state - $state - $state - - - - - Expression::parse($parser, $list) - - - expr)]]> - expr)]]> - - - - - name]]> - - - DataType::parse($parser, $list) - - - name)]]> - - - - - true, - 'parseField' => 'table', - ], - )]]> - true, - 'parseField' => 'table', - ], - )]]> - - - old)]]> - - - - - expr]]> - - - value === ',']]> - - $table @@ -447,6 +334,119 @@ $type + + + $state === 1 + + + + + name]]> + name]]> + + + + + $ret + + + Expression[] + + + $expr + $expr + $expr + + + $state === 1 + + + + + Expression::parse($parser, $list) + + + expr)]]> + expr)]]> + + + + + type]]> + + + + + keyword]]]> + keyword]]]> + + + ArrayObj::parse($parser, $list) + + + 'table'])]]> + + + keyword])]]> + keyword])]]> + + + $state + $state + $state + + + + + Expression::parse($parser, $list) + + + expr)]]> + expr)]]> + + + + + name]]> + + + DataType::parse($parser, $list) + + + name)]]> + + + + + true, + 'parseField' => 'table', + ], + )]]> + true, + 'parseField' => 'table', + ], + )]]> + + + old)]]> + + + + + expr]]> + + + value === ',']]> + + $expr diff --git a/src/Components/CaseExpression.php b/src/Components/CaseExpression.php index 60ff6236..fa309371 100644 --- a/src/Components/CaseExpression.php +++ b/src/Components/CaseExpression.php @@ -5,7 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; -use PhpMyAdmin\SqlParser\Components\Lists\Conditions; +use PhpMyAdmin\SqlParser\Components\Parsers\Conditions; use PhpMyAdmin\SqlParser\Context; use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; diff --git a/src/Components/IntoKeyword.php b/src/Components/IntoKeyword.php index 3b828d16..39c210c3 100644 --- a/src/Components/IntoKeyword.php +++ b/src/Components/IntoKeyword.php @@ -5,7 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; -use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; +use PhpMyAdmin\SqlParser\Components\Parsers\ExpressionArray; use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Token; diff --git a/src/Components/JoinKeyword.php b/src/Components/JoinKeyword.php index 29a551a4..f908f72f 100644 --- a/src/Components/JoinKeyword.php +++ b/src/Components/JoinKeyword.php @@ -5,7 +5,7 @@ namespace PhpMyAdmin\SqlParser\Components; use PhpMyAdmin\SqlParser\Component; -use PhpMyAdmin\SqlParser\Components\Lists\Conditions; +use PhpMyAdmin\SqlParser\Components\Parsers\Conditions; use function array_search; diff --git a/src/Components/Lists/Array2d.php b/src/Components/Parsers/Array2d.php similarity index 98% rename from src/Components/Lists/Array2d.php rename to src/Components/Parsers/Array2d.php index 8258cb30..24ac71a5 100644 --- a/src/Components/Lists/Array2d.php +++ b/src/Components/Parsers/Array2d.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components\Lists; +namespace PhpMyAdmin\SqlParser\Components\Parsers; use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Parseable; diff --git a/src/Components/Lists/Conditions.php b/src/Components/Parsers/Conditions.php similarity index 99% rename from src/Components/Lists/Conditions.php rename to src/Components/Parsers/Conditions.php index fc6c9178..9bf37a1e 100644 --- a/src/Components/Lists/Conditions.php +++ b/src/Components/Parsers/Conditions.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components\Lists; +namespace PhpMyAdmin\SqlParser\Components\Parsers; use PhpMyAdmin\SqlParser\Components\Condition; use PhpMyAdmin\SqlParser\Parseable; diff --git a/src/Components/Lists/CreateDefinitions.php b/src/Components/Parsers/CreateDefinitions.php similarity index 99% rename from src/Components/Lists/CreateDefinitions.php rename to src/Components/Parsers/CreateDefinitions.php index abcf4113..f1b5c4d9 100644 --- a/src/Components/Lists/CreateDefinitions.php +++ b/src/Components/Parsers/CreateDefinitions.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components\Lists; +namespace PhpMyAdmin\SqlParser\Components\Parsers; use PhpMyAdmin\SqlParser\Components\CreateDefinition; use PhpMyAdmin\SqlParser\Components\DataType; diff --git a/src/Components/Lists/ExpressionArray.php b/src/Components/Parsers/ExpressionArray.php similarity index 98% rename from src/Components/Lists/ExpressionArray.php rename to src/Components/Parsers/ExpressionArray.php index 8c03710b..5dffef94 100644 --- a/src/Components/Lists/ExpressionArray.php +++ b/src/Components/Parsers/ExpressionArray.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components\Lists; +namespace PhpMyAdmin\SqlParser\Components\Parsers; use PhpMyAdmin\SqlParser\Components\CaseExpression; use PhpMyAdmin\SqlParser\Components\Expression; diff --git a/src/Components/Lists/GroupKeywords.php b/src/Components/Parsers/GroupKeywords.php similarity index 98% rename from src/Components/Lists/GroupKeywords.php rename to src/Components/Parsers/GroupKeywords.php index 5e6bffcf..5d8e4a65 100644 --- a/src/Components/Lists/GroupKeywords.php +++ b/src/Components/Parsers/GroupKeywords.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components\Lists; +namespace PhpMyAdmin\SqlParser\Components\Parsers; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\GroupKeyword; diff --git a/src/Components/Lists/IndexHints.php b/src/Components/Parsers/IndexHints.php similarity index 98% rename from src/Components/Lists/IndexHints.php rename to src/Components/Parsers/IndexHints.php index c6b1f084..d78fb375 100644 --- a/src/Components/Lists/IndexHints.php +++ b/src/Components/Parsers/IndexHints.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components\Lists; +namespace PhpMyAdmin\SqlParser\Components\Parsers; use PhpMyAdmin\SqlParser\Components\IndexHint; use PhpMyAdmin\SqlParser\Parseable; diff --git a/src/Components/Lists/JoinKeywords.php b/src/Components/Parsers/JoinKeywords.php similarity index 98% rename from src/Components/Lists/JoinKeywords.php rename to src/Components/Parsers/JoinKeywords.php index c5d6d21c..5b1ae38b 100644 --- a/src/Components/Lists/JoinKeywords.php +++ b/src/Components/Parsers/JoinKeywords.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components\Lists; +namespace PhpMyAdmin\SqlParser\Components\Parsers; use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Components\Expression; diff --git a/src/Components/Lists/OrderKeywords.php b/src/Components/Parsers/OrderKeywords.php similarity index 98% rename from src/Components/Lists/OrderKeywords.php rename to src/Components/Parsers/OrderKeywords.php index fcb8571c..54890d3d 100644 --- a/src/Components/Lists/OrderKeywords.php +++ b/src/Components/Parsers/OrderKeywords.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components\Lists; +namespace PhpMyAdmin\SqlParser\Components\Parsers; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\OrderKeyword; diff --git a/src/Components/Lists/ParameterDefinitions.php b/src/Components/Parsers/ParameterDefinitions.php similarity index 98% rename from src/Components/Lists/ParameterDefinitions.php rename to src/Components/Parsers/ParameterDefinitions.php index 2ec2ec3f..ad0b068b 100644 --- a/src/Components/Lists/ParameterDefinitions.php +++ b/src/Components/Parsers/ParameterDefinitions.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components\Lists; +namespace PhpMyAdmin\SqlParser\Components\Parsers; use PhpMyAdmin\SqlParser\Components\DataType; use PhpMyAdmin\SqlParser\Components\ParameterDefinition; diff --git a/src/Components/Lists/RenameOperations.php b/src/Components/Parsers/RenameOperations.php similarity index 98% rename from src/Components/Lists/RenameOperations.php rename to src/Components/Parsers/RenameOperations.php index 058f1a38..097ddbc7 100644 --- a/src/Components/Lists/RenameOperations.php +++ b/src/Components/Parsers/RenameOperations.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components\Lists; +namespace PhpMyAdmin\SqlParser\Components\Parsers; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\RenameOperation; diff --git a/src/Components/Lists/SetOperations.php b/src/Components/Parsers/SetOperations.php similarity index 98% rename from src/Components/Lists/SetOperations.php rename to src/Components/Parsers/SetOperations.php index 4ea3a71e..1d8e4a61 100644 --- a/src/Components/Lists/SetOperations.php +++ b/src/Components/Parsers/SetOperations.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components\Lists; +namespace PhpMyAdmin\SqlParser\Components\Parsers; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\SetOperation; diff --git a/src/Parser.php b/src/Parser.php index 0a6bc3b1..f9d2e1c9 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -158,12 +158,12 @@ class Parser 'options' => ['parseField' => 'table'], ], 'ANALYZE' => [ - 'class' => Components\Lists\ExpressionArray::class, + 'class' => Components\Parsers\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], 'BACKUP' => [ - 'class' => Components\Lists\ExpressionArray::class, + 'class' => Components\Parsers\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], @@ -172,43 +172,43 @@ class Parser 'field' => 'call', ], 'CHECK' => [ - 'class' => Components\Lists\ExpressionArray::class, + 'class' => Components\Parsers\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], 'CHECKSUM' => [ - 'class' => Components\Lists\ExpressionArray::class, + 'class' => Components\Parsers\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], 'CROSS JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'DROP' => [ - 'class' => Components\Lists\ExpressionArray::class, + 'class' => Components\Parsers\ExpressionArray::class, 'field' => 'fields', 'options' => ['parseField' => 'table'], ], 'FORCE' => [ - 'class' => Components\Lists\IndexHints::class, + 'class' => Components\Parsers\IndexHints::class, 'field' => 'index_hints', ], 'FROM' => [ - 'class' => Components\Lists\ExpressionArray::class, + 'class' => Components\Parsers\ExpressionArray::class, 'field' => 'from', 'options' => ['field' => 'table'], ], 'GROUP BY' => [ - 'class' => Components\Lists\GroupKeywords::class, + 'class' => Components\Parsers\GroupKeywords::class, 'field' => 'group', ], 'HAVING' => [ - 'class' => Components\Lists\Conditions::class, + 'class' => Components\Parsers\Conditions::class, 'field' => 'having', ], 'IGNORE' => [ - 'class' => Components\Lists\IndexHints::class, + 'class' => Components\Parsers\IndexHints::class, 'field' => 'index_hints', ], 'INTO' => [ @@ -216,15 +216,15 @@ class Parser 'field' => 'into', ], 'JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'LEFT JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'LEFT OUTER JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'ON' => [ @@ -233,47 +233,47 @@ class Parser 'options' => ['parseField' => 'table'], ], 'RIGHT JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'RIGHT OUTER JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'INNER JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'FULL JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'FULL OUTER JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'NATURAL JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'NATURAL LEFT JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'NATURAL RIGHT JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'NATURAL LEFT OUTER JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'NATURAL RIGHT OUTER JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'STRAIGHT_JOIN' => [ - 'class' => Components\Lists\JoinKeywords::class, + 'class' => Components\Parsers\JoinKeywords::class, 'field' => 'join', ], 'LIMIT' => [ @@ -281,12 +281,12 @@ class Parser 'field' => 'limit', ], 'OPTIMIZE' => [ - 'class' => Components\Lists\ExpressionArray::class, + 'class' => Components\Parsers\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], 'ORDER BY' => [ - 'class' => Components\Lists\OrderKeywords::class, + 'class' => Components\Parsers\OrderKeywords::class, 'field' => 'order', ], 'PARTITION' => [ @@ -298,25 +298,25 @@ class Parser 'field' => 'procedure', ], 'RENAME' => [ - 'class' => Components\Lists\RenameOperations::class, + 'class' => Components\Parsers\RenameOperations::class, 'field' => 'renames', ], 'REPAIR' => [ - 'class' => Components\Lists\ExpressionArray::class, + 'class' => Components\Parsers\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], 'RESTORE' => [ - 'class' => Components\Lists\ExpressionArray::class, + 'class' => Components\Parsers\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], 'SET' => [ - 'class' => Components\Lists\SetOperations::class, + 'class' => Components\Parsers\SetOperations::class, 'field' => 'set', ], 'SELECT' => [ - 'class' => Components\Lists\ExpressionArray::class, + 'class' => Components\Parsers\ExpressionArray::class, 'field' => 'expr', ], 'TRUNCATE' => [ @@ -325,24 +325,24 @@ class Parser 'options' => ['parseField' => 'table'], ], 'UPDATE' => [ - 'class' => Components\Lists\ExpressionArray::class, + 'class' => Components\Parsers\ExpressionArray::class, 'field' => 'tables', 'options' => ['parseField' => 'table'], ], 'USE' => [ - 'class' => Components\Lists\IndexHints::class, + 'class' => Components\Parsers\IndexHints::class, 'field' => 'index_hints', ], 'VALUE' => [ - 'class' => Components\Lists\Array2d::class, + 'class' => Components\Parsers\Array2d::class, 'field' => 'values', ], 'VALUES' => [ - 'class' => Components\Lists\Array2d::class, + 'class' => Components\Parsers\Array2d::class, 'field' => 'values', ], 'WHERE' => [ - 'class' => Components\Lists\Conditions::class, + 'class' => Components\Parsers\Conditions::class, 'field' => 'where', ], ]; diff --git a/src/Statements/CreateStatement.php b/src/Statements/CreateStatement.php index 6c41c9b0..ff12dc86 100644 --- a/src/Statements/CreateStatement.php +++ b/src/Statements/CreateStatement.php @@ -8,10 +8,10 @@ use PhpMyAdmin\SqlParser\Components\CreateDefinition; use PhpMyAdmin\SqlParser\Components\DataType; use PhpMyAdmin\SqlParser\Components\Expression; -use PhpMyAdmin\SqlParser\Components\Lists\CreateDefinitions; -use PhpMyAdmin\SqlParser\Components\Lists\ParameterDefinitions; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\ParameterDefinition; +use PhpMyAdmin\SqlParser\Components\Parsers\CreateDefinitions; +use PhpMyAdmin\SqlParser\Components\Parsers\ParameterDefinitions; use PhpMyAdmin\SqlParser\Components\PartitionDefinition; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statement; diff --git a/src/Statements/DeleteStatement.php b/src/Statements/DeleteStatement.php index d06b8fac..a93629cc 100644 --- a/src/Statements/DeleteStatement.php +++ b/src/Statements/DeleteStatement.php @@ -9,12 +9,12 @@ use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\JoinKeyword; use PhpMyAdmin\SqlParser\Components\Limit; -use PhpMyAdmin\SqlParser\Components\Lists\Conditions; -use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; -use PhpMyAdmin\SqlParser\Components\Lists\JoinKeywords; -use PhpMyAdmin\SqlParser\Components\Lists\OrderKeywords; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\OrderKeyword; +use PhpMyAdmin\SqlParser\Components\Parsers\Conditions; +use PhpMyAdmin\SqlParser\Components\Parsers\ExpressionArray; +use PhpMyAdmin\SqlParser\Components\Parsers\JoinKeywords; +use PhpMyAdmin\SqlParser\Components\Parsers\OrderKeywords; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statement; use PhpMyAdmin\SqlParser\TokensList; diff --git a/src/Statements/InsertStatement.php b/src/Statements/InsertStatement.php index 91c2f4d0..5b630ad5 100644 --- a/src/Statements/InsertStatement.php +++ b/src/Statements/InsertStatement.php @@ -6,9 +6,9 @@ use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Components\IntoKeyword; -use PhpMyAdmin\SqlParser\Components\Lists\Array2d; -use PhpMyAdmin\SqlParser\Components\Lists\SetOperations; use PhpMyAdmin\SqlParser\Components\OptionsArray; +use PhpMyAdmin\SqlParser\Components\Parsers\Array2d; +use PhpMyAdmin\SqlParser\Components\Parsers\SetOperations; use PhpMyAdmin\SqlParser\Components\SetOperation; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statement; diff --git a/src/Statements/LoadStatement.php b/src/Statements/LoadStatement.php index 41bd3a97..a0948450 100644 --- a/src/Statements/LoadStatement.php +++ b/src/Statements/LoadStatement.php @@ -6,9 +6,9 @@ use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Components\Expression; -use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; -use PhpMyAdmin\SqlParser\Components\Lists\SetOperations; use PhpMyAdmin\SqlParser\Components\OptionsArray; +use PhpMyAdmin\SqlParser\Components\Parsers\ExpressionArray; +use PhpMyAdmin\SqlParser\Components\Parsers\SetOperations; use PhpMyAdmin\SqlParser\Components\SetOperation; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statement; diff --git a/src/Statements/RenameStatement.php b/src/Statements/RenameStatement.php index 7cf06af7..246357a2 100644 --- a/src/Statements/RenameStatement.php +++ b/src/Statements/RenameStatement.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Statements; -use PhpMyAdmin\SqlParser\Components\Lists\RenameOperations; +use PhpMyAdmin\SqlParser\Components\Parsers\RenameOperations; use PhpMyAdmin\SqlParser\Components\RenameOperation; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statement; diff --git a/src/Statements/ReplaceStatement.php b/src/Statements/ReplaceStatement.php index 3cb53be5..a7f0bc3c 100644 --- a/src/Statements/ReplaceStatement.php +++ b/src/Statements/ReplaceStatement.php @@ -6,9 +6,9 @@ use PhpMyAdmin\SqlParser\Components\ArrayObj; use PhpMyAdmin\SqlParser\Components\IntoKeyword; -use PhpMyAdmin\SqlParser\Components\Lists\Array2d; -use PhpMyAdmin\SqlParser\Components\Lists\SetOperations; use PhpMyAdmin\SqlParser\Components\OptionsArray; +use PhpMyAdmin\SqlParser\Components\Parsers\Array2d; +use PhpMyAdmin\SqlParser\Components\Parsers\SetOperations; use PhpMyAdmin\SqlParser\Components\SetOperation; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statement; diff --git a/src/Statements/SetStatement.php b/src/Statements/SetStatement.php index 9603a890..8dc6746b 100644 --- a/src/Statements/SetStatement.php +++ b/src/Statements/SetStatement.php @@ -4,8 +4,8 @@ namespace PhpMyAdmin\SqlParser\Statements; -use PhpMyAdmin\SqlParser\Components\Lists\SetOperations; use PhpMyAdmin\SqlParser\Components\OptionsArray; +use PhpMyAdmin\SqlParser\Components\Parsers\SetOperations; use PhpMyAdmin\SqlParser\Components\SetOperation; use PhpMyAdmin\SqlParser\Statement; diff --git a/src/Statements/WithStatement.php b/src/Statements/WithStatement.php index 242e4c53..81e79569 100644 --- a/src/Statements/WithStatement.php +++ b/src/Statements/WithStatement.php @@ -4,8 +4,8 @@ namespace PhpMyAdmin\SqlParser\Statements; -use PhpMyAdmin\SqlParser\Components\Lists\Array2d; use PhpMyAdmin\SqlParser\Components\OptionsArray; +use PhpMyAdmin\SqlParser\Components\Parsers\Array2d; use PhpMyAdmin\SqlParser\Components\WithKeyword; use PhpMyAdmin\SqlParser\Exceptions\ParserException; use PhpMyAdmin\SqlParser\Parser; diff --git a/src/Utils/Routine.php b/src/Utils/Routine.php index ae760147..3017c92e 100644 --- a/src/Utils/Routine.php +++ b/src/Utils/Routine.php @@ -5,7 +5,7 @@ namespace PhpMyAdmin\SqlParser\Utils; use PhpMyAdmin\SqlParser\Components\DataType; -use PhpMyAdmin\SqlParser\Components\Lists\ParameterDefinitions; +use PhpMyAdmin\SqlParser\Components\Parsers\ParameterDefinitions; use PhpMyAdmin\SqlParser\Lexer; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statements\CreateStatement; diff --git a/tests/Builder/CreateStatementTest.php b/tests/Builder/CreateStatementTest.php index e18ec554..494a16db 100644 --- a/tests/Builder/CreateStatementTest.php +++ b/tests/Builder/CreateStatementTest.php @@ -8,9 +8,9 @@ use PhpMyAdmin\SqlParser\Components\DataType; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\Key; -use PhpMyAdmin\SqlParser\Components\Lists\CreateDefinitions; -use PhpMyAdmin\SqlParser\Components\Lists\ParameterDefinitions; use PhpMyAdmin\SqlParser\Components\OptionsArray; +use PhpMyAdmin\SqlParser\Components\Parsers\CreateDefinitions; +use PhpMyAdmin\SqlParser\Components\Parsers\ParameterDefinitions; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statements\CreateStatement; use PhpMyAdmin\SqlParser\Tests\TestCase; diff --git a/tests/Components/Array2dTest.php b/tests/Components/Array2dTest.php index a44e037c..2587fd24 100644 --- a/tests/Components/Array2dTest.php +++ b/tests/Components/Array2dTest.php @@ -5,7 +5,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; use PhpMyAdmin\SqlParser\Components\ArrayObj; -use PhpMyAdmin\SqlParser\Components\Lists\Array2d; +use PhpMyAdmin\SqlParser\Components\Parsers\Array2d; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Tests\TestCase; diff --git a/tests/Components/ConditionTest.php b/tests/Components/ConditionTest.php index d40c8a5e..12dc928d 100644 --- a/tests/Components/ConditionTest.php +++ b/tests/Components/ConditionTest.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\Lists\Conditions; +use PhpMyAdmin\SqlParser\Components\Parsers\Conditions; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Tests\TestCase; diff --git a/tests/Components/CreateDefinitionTest.php b/tests/Components/CreateDefinitionTest.php index 1cd7e008..fb087ce1 100644 --- a/tests/Components/CreateDefinitionTest.php +++ b/tests/Components/CreateDefinitionTest.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\Lists\CreateDefinitions; +use PhpMyAdmin\SqlParser\Components\Parsers\CreateDefinitions; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statements\CreateStatement; use PhpMyAdmin\SqlParser\Tests\TestCase; diff --git a/tests/Components/ExpressionArrayTest.php b/tests/Components/ExpressionArrayTest.php index 3f668a23..cfe19717 100644 --- a/tests/Components/ExpressionArrayTest.php +++ b/tests/Components/ExpressionArrayTest.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\Lists\ExpressionArray; +use PhpMyAdmin\SqlParser\Components\Parsers\ExpressionArray; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Tests\TestCase; diff --git a/tests/Components/GroupKeywordTest.php b/tests/Components/GroupKeywordTest.php index 2344790c..4cc8af0a 100644 --- a/tests/Components/GroupKeywordTest.php +++ b/tests/Components/GroupKeywordTest.php @@ -7,7 +7,7 @@ use Generator; use PhpMyAdmin\SqlParser\Components\Expression; use PhpMyAdmin\SqlParser\Components\GroupKeyword; -use PhpMyAdmin\SqlParser\Components\Lists\GroupKeywords; +use PhpMyAdmin\SqlParser\Components\Parsers\GroupKeywords; use PhpMyAdmin\SqlParser\Tests\TestCase; use PHPUnit\Framework\Attributes\DataProvider; diff --git a/tests/Components/JoinKeywordTest.php b/tests/Components/JoinKeywordTest.php index 45c44662..a58c5b4e 100644 --- a/tests/Components/JoinKeywordTest.php +++ b/tests/Components/JoinKeywordTest.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\Lists\JoinKeywords; +use PhpMyAdmin\SqlParser\Components\Parsers\JoinKeywords; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Tests\TestCase; diff --git a/tests/Components/OrderKeywordTest.php b/tests/Components/OrderKeywordTest.php index 454899cd..336e92ab 100644 --- a/tests/Components/OrderKeywordTest.php +++ b/tests/Components/OrderKeywordTest.php @@ -5,8 +5,8 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; use PhpMyAdmin\SqlParser\Components\Expression; -use PhpMyAdmin\SqlParser\Components\Lists\OrderKeywords; use PhpMyAdmin\SqlParser\Components\OrderKeyword; +use PhpMyAdmin\SqlParser\Components\Parsers\OrderKeywords; use PhpMyAdmin\SqlParser\Tests\TestCase; class OrderKeywordTest extends TestCase diff --git a/tests/Components/ParameterDefinitionTest.php b/tests/Components/ParameterDefinitionTest.php index fbbe0101..67ab9302 100644 --- a/tests/Components/ParameterDefinitionTest.php +++ b/tests/Components/ParameterDefinitionTest.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\Lists\ParameterDefinitions; +use PhpMyAdmin\SqlParser\Components\Parsers\ParameterDefinitions; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Tests\TestCase; diff --git a/tests/Components/RenameOperationTest.php b/tests/Components/RenameOperationTest.php index 302e20a4..ea56f374 100644 --- a/tests/Components/RenameOperationTest.php +++ b/tests/Components/RenameOperationTest.php @@ -4,7 +4,7 @@ namespace PhpMyAdmin\SqlParser\Tests\Components; -use PhpMyAdmin\SqlParser\Components\Lists\RenameOperations; +use PhpMyAdmin\SqlParser\Components\Parsers\RenameOperations; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Tests\TestCase; From ce0191371dda0bd96931aceee2b915646cdd0a5e Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Tue, 16 Jan 2024 18:18:33 +0100 Subject: [PATCH 15/17] Move UnionKeyword to Parsers Signed-off-by: Kamil Tekiela --- .../UnionKeywords.php} | 18 ++++-------------- src/Parser.php | 10 +++++----- 2 files changed, 9 insertions(+), 19 deletions(-) rename src/Components/{UnionKeyword.php => Parsers/UnionKeywords.php} (72%) diff --git a/src/Components/UnionKeyword.php b/src/Components/Parsers/UnionKeywords.php similarity index 72% rename from src/Components/UnionKeyword.php rename to src/Components/Parsers/UnionKeywords.php index 11f81707..b421d060 100644 --- a/src/Components/UnionKeyword.php +++ b/src/Components/Parsers/UnionKeywords.php @@ -2,21 +2,21 @@ declare(strict_types=1); -namespace PhpMyAdmin\SqlParser\Components; +namespace PhpMyAdmin\SqlParser\Components\Parsers; -use PhpMyAdmin\SqlParser\Component; use PhpMyAdmin\SqlParser\Parseable; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\Translator; use RuntimeException; +use Stringable; use function implode; /** * `UNION` keyword builder. */ -final class UnionKeyword implements Component, Parseable +final class UnionKeywords implements Parseable { /** * Parses the tokens contained in the given list in the context of the given parser. @@ -32,12 +32,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = throw new RuntimeException(Translator::gettext('Not implemented yet.')); } - public function build(): string - { - throw new RuntimeException(Translator::gettext('Not implemented yet.')); - } - - /** @param UnionKeyword[][] $component the component to be built */ + /** @param list $component the component to be built */ public static function buildAll(array $component): string { $tmp = []; @@ -47,9 +42,4 @@ public static function buildAll(array $component): string return implode(' ', $tmp); } - - public function __toString(): string - { - return $this->build(); - } } diff --git a/src/Parser.php b/src/Parser.php index f9d2e1c9..1a561723 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -131,23 +131,23 @@ class Parser ], 'INTERSECT' => [ - 'class' => Components\UnionKeyword::class, + 'class' => Components\Parsers\UnionKeywords::class, 'field' => 'union', ], 'EXCEPT' => [ - 'class' => Components\UnionKeyword::class, + 'class' => Components\Parsers\UnionKeywords::class, 'field' => 'union', ], 'UNION' => [ - 'class' => Components\UnionKeyword::class, + 'class' => Components\Parsers\UnionKeywords::class, 'field' => 'union', ], 'UNION ALL' => [ - 'class' => Components\UnionKeyword::class, + 'class' => Components\Parsers\UnionKeywords::class, 'field' => 'union', ], 'UNION DISTINCT' => [ - 'class' => Components\UnionKeyword::class, + 'class' => Components\Parsers\UnionKeywords::class, 'field' => 'union', ], From 6cbf59a02d12c560c5d3db06a9f36ad12a1edc25 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 20 Jan 2024 01:49:56 +0100 Subject: [PATCH 16/17] Remove redundant comparisons Signed-off-by: Kamil Tekiela --- psalm-baseline.xml | 5 ----- src/Components/Parsers/CreateDefinitions.php | 2 +- src/Components/Parsers/GroupKeywords.php | 2 +- src/Components/Parsers/JoinKeywords.php | 2 +- src/Components/Parsers/OrderKeywords.php | 2 +- src/Components/Parsers/ParameterDefinitions.php | 2 +- src/Components/Parsers/RenameOperations.php | 2 +- src/Components/Parsers/SetOperations.php | 2 +- 8 files changed, 7 insertions(+), 12 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 92bcf53a..9621ec5a 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -390,11 +390,6 @@ keyword])]]> keyword])]]> - - $state - $state - $state - diff --git a/src/Components/Parsers/CreateDefinitions.php b/src/Components/Parsers/CreateDefinitions.php index f1b5c4d9..ed440e51 100644 --- a/src/Components/Parsers/CreateDefinitions.php +++ b/src/Components/Parsers/CreateDefinitions.php @@ -210,7 +210,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = } $state = 5; - } elseif ($state === 5) { + } else { if (! empty($expr->type) || ! empty($expr->key)) { $ret[] = $expr; } diff --git a/src/Components/Parsers/GroupKeywords.php b/src/Components/Parsers/GroupKeywords.php index 5d8e4a65..843532d0 100644 --- a/src/Components/Parsers/GroupKeywords.php +++ b/src/Components/Parsers/GroupKeywords.php @@ -62,7 +62,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = if ($state === 0) { $expr->expr = Expression::parse($parser, $list); $state = 1; - } elseif ($state === 1) { + } else { if ( ($token->type === TokenType::Keyword) && (($token->keyword === 'ASC') || ($token->keyword === 'DESC')) diff --git a/src/Components/Parsers/JoinKeywords.php b/src/Components/Parsers/JoinKeywords.php index 5b1ae38b..a2e17ef6 100644 --- a/src/Components/Parsers/JoinKeywords.php +++ b/src/Components/Parsers/JoinKeywords.php @@ -111,7 +111,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = $ret[] = $expr; $expr = new JoinKeyword(); $state = 0; - } elseif ($state === 4) { + } else { $expr->using = ArrayObj::parse($parser, $list); $ret[] = $expr; $expr = new JoinKeyword(); diff --git a/src/Components/Parsers/OrderKeywords.php b/src/Components/Parsers/OrderKeywords.php index 54890d3d..087a2420 100644 --- a/src/Components/Parsers/OrderKeywords.php +++ b/src/Components/Parsers/OrderKeywords.php @@ -62,7 +62,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = if ($state === 0) { $expr->expr = Expression::parse($parser, $list); $state = 1; - } elseif ($state === 1) { + } else { if ( ($token->type === TokenType::Keyword) && (($token->keyword === 'ASC') || ($token->keyword === 'DESC')) diff --git a/src/Components/Parsers/ParameterDefinitions.php b/src/Components/Parsers/ParameterDefinitions.php index ad0b068b..6fb71d01 100644 --- a/src/Components/Parsers/ParameterDefinitions.php +++ b/src/Components/Parsers/ParameterDefinitions.php @@ -82,7 +82,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = } elseif ($state === 2) { $expr->type = DataType::parse($parser, $list); $state = 3; - } elseif ($state === 3) { + } else { $ret[] = $expr; $expr = new ParameterDefinition(); if ($token->value === ',') { diff --git a/src/Components/Parsers/RenameOperations.php b/src/Components/Parsers/RenameOperations.php index 097ddbc7..09db93bb 100644 --- a/src/Components/Parsers/RenameOperations.php +++ b/src/Components/Parsers/RenameOperations.php @@ -98,7 +98,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = } $state = 3; - } elseif ($state === 3) { + } else { if (($token->type !== TokenType::Operator) || ($token->value !== ',')) { break; } diff --git a/src/Components/Parsers/SetOperations.php b/src/Components/Parsers/SetOperations.php index 1d8e4a61..327f5bb7 100644 --- a/src/Components/Parsers/SetOperations.php +++ b/src/Components/Parsers/SetOperations.php @@ -84,7 +84,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = } elseif ($token->value === ',') { $commaLastSeenAt = $token; } - } elseif ($state === 1) { + } else { $tmp = Expression::parse( $parser, $list, From 33e49e6a40c913ab1d6accf1fc8c9008642a3779 Mon Sep 17 00:00:00 2001 From: Kamil Tekiela Date: Sat, 20 Jan 2024 18:54:08 +0100 Subject: [PATCH 17/17] Update phpstan-baseline.neon Signed-off-by: Kamil Tekiela --- phpstan-baseline.neon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 95f776f5..86f7ef46 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -571,7 +571,7 @@ parameters: path: src/Statement.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Statement\\:\\:\\$options \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\OptionsArray\\|null\\) does not accept mixed\\.$#" + message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Statement\\:\\:\\$options \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\OptionsArray\\|null\\) does not accept array\\\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\ArrayObj\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\FunctionCall\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\IntoKeyword\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\Limit\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\OptionsArray\\|null\\.$#" count: 1 path: src/Statement.php