Skip to content

Commit

Permalink
Merge branch '5.11.x'
Browse files Browse the repository at this point in the history
Signed-off-by: Maurício Meneghini Fauth <[email protected]>
  • Loading branch information
MauricioFauth committed Sep 19, 2024
2 parents 91d2bbf + a5a74e7 commit 1e1693e
Show file tree
Hide file tree
Showing 20 changed files with 1,488 additions and 65 deletions.
2 changes: 1 addition & 1 deletion phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ parameters:
path: src/Statements/SelectStatement.php

-
message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Statements\\\\SelectStatement\\:\\:\\$expr \\(array\\<PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\>\\) does not accept array\\<PhpMyAdmin\\\\SqlParser\\\\Component\\>\\|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\\.$#"
message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Statements\\\\SelectStatement\\:\\:\\$expr \\(array\\<PhpMyAdmin\\\\SqlParser\\\\Components\\\\CaseExpression\\|PhpMyAdmin\\\\SqlParser\\\\Components\\\\Expression\\>\\) does not accept array\\<PhpMyAdmin\\\\SqlParser\\\\Component\\>\\|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/Statements/SelectStatement.php

Expand Down
14 changes: 13 additions & 1 deletion psalm-baseline.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="5.25.0@01a8eb06b9e9cc6cfb6a320bf9fb14331919d505">
<files psalm-version="5.26.1@d747f6500b38ac4f7dfc5edbcae6e4b637d7add0">
<file src="src/Components/AlterOperation.php">
<PossiblyNullReference>
<code><![CDATA[has]]></code>
Expand Down Expand Up @@ -859,6 +859,15 @@
</PossiblyNullOperand>
</file>
<file src="src/Statements/SelectStatement.php">
<MixedArrayOffset>
<code><![CDATA[$retval[$thisDb]['tables'][$thisTable]['columns'][$expr->column]]]></code>
<code><![CDATA[$table['columns'][$expr->column]]]></code>
<code><![CDATA[$tables[$thisDb][$expr->table]]]></code>
</MixedArrayOffset>
<MixedReturnTypeCoercion>
<code><![CDATA[$retval]]></code>
<code><![CDATA[array<string, array<string, array<string, array<string, array<string, string>|string|null>>|null>>]]></code>
</MixedReturnTypeCoercion>
<PossiblyNullArrayOffset>
<code><![CDATA[$tables[$thisDb]]]></code>
</PossiblyNullArrayOffset>
Expand Down Expand Up @@ -1092,6 +1101,9 @@
<InvalidNullableReturnType>
<code><![CDATA[int]]></code>
</InvalidNullableReturnType>
<MixedArrayOffset>
<code><![CDATA[$tableAliases[$expr->table]]]></code>
</MixedArrayOffset>
<MixedAssignment>
<code><![CDATA[$expr]]></code>
<code><![CDATA[$expressions[]]]></code>
Expand Down
22 changes: 17 additions & 5 deletions src/Lexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,7 @@ public function parseNumber(): Token|null
// 1 --------------------[ + or - ]-------------------> 1
// 1 -------------------[ 0x or 0X ]------------------> 2
// 1 --------------------[ 0 to 9 ]-------------------> 3
// 1 -----------------------[ . ]---------------------> 4
// 1 -----------------------[ . ]---------------------> 10
// 1 -----------------------[ b ]---------------------> 7
//
// 2 --------------------[ 0 to F ]-------------------> 2
Expand All @@ -718,11 +718,16 @@ public function parseNumber(): Token|null
// 8 --------------------[ 0 or 1 ]-------------------> 8
// 8 -----------------------[ ' ]---------------------> 9
//
// 10 -------------------[ 0 to 9 ]-------------------> 4
//
// State 1 may be reached by negative numbers.
// State 2 is reached only by hex numbers.
// State 4 is reached only by float numbers.
// State 5 is reached only by numbers in approximate form.
// State 7 is reached only by numbers in bit representation.
// State 10 is a forced proxy to state 4 ensuring a starting dot (= "0.something") precedes a digit, and not "e"
// or "E" causing wrongly interpreted scientific notation (".e[0 to 9]" is invalid). Such invalid notation could
// break the lexer when table names under a given database context starts with ".e[0-9]".
//
// Valid final states are: 2, 3, 4 and 6. Any parsing that finished in a
// state other than these is invalid.
Expand All @@ -745,7 +750,7 @@ public function parseNumber(): Token|null
} elseif ($this->str[$this->last] >= '0' && $this->str[$this->last] <= '9') {
$state = 3;
} elseif ($this->str[$this->last] === '.') {
$state = 4;
$state = 10;
} elseif ($this->str[$this->last] === 'b') {
$state = 7;
} elseif ($this->str[$this->last] !== '+') {
Expand All @@ -772,7 +777,7 @@ public function parseNumber(): Token|null
($this->str[$this->last] >= 'a' && $this->str[$this->last] <= 'z')
|| ($this->str[$this->last] >= 'A' && $this->str[$this->last] <= 'Z')
) {
// A number can't be directly followed by a letter
// A number can't be directly followed by a letter
$state = -$state;
} elseif ($this->str[$this->last] < '0' || $this->str[$this->last] > '9') {
// Just digits and `.`, `e` and `E` are valid characters.
Expand All @@ -786,7 +791,7 @@ public function parseNumber(): Token|null
($this->str[$this->last] >= 'a' && $this->str[$this->last] <= 'z')
|| ($this->str[$this->last] >= 'A' && $this->str[$this->last] <= 'Z')
) {
// A number can't be directly followed by a letter
// A number can't be directly followed by a letter
$state = -$state;
} elseif ($this->str[$this->last] < '0' || $this->str[$this->last] > '9') {
// Just digits, `e` and `E` are valid characters.
Expand All @@ -803,7 +808,7 @@ public function parseNumber(): Token|null
($this->str[$this->last] >= 'a' && $this->str[$this->last] <= 'z')
|| ($this->str[$this->last] >= 'A' && $this->str[$this->last] <= 'Z')
) {
// A number can't be directly followed by a letter
// A number can't be directly followed by a letter
$state = -$state;
} else {
break;
Expand All @@ -828,6 +833,13 @@ public function parseNumber(): Token|null
}
} elseif ($state === 9) {
break;
} elseif ($state === 10) {
$flags |= Token::FLAG_NUMBER_FLOAT;
if ($this->str[$this->last] < '0' || $this->str[$this->last] > '9') {
break;
}

$state = 4;
}

$token .= $this->str[$this->last];
Expand Down
2 changes: 1 addition & 1 deletion src/Parsers/AlterOperations.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ final class AlterOperations implements Parseable
'BY' => 2,
'FOREIGN' => 2,
'FULLTEXT' => 2,
'KEY' => 2,
'KEY' => [2, 'var'],
'KEYS' => 2,
'PARTITION' => 2,
'PARTITION BY' => 2,
Expand Down
3 changes: 2 additions & 1 deletion src/Statements/SelectStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace PhpMyAdmin\SqlParser\Statements;

use PhpMyAdmin\SqlParser\Components\ArrayObj;
use PhpMyAdmin\SqlParser\Components\CaseExpression;
use PhpMyAdmin\SqlParser\Components\Condition;
use PhpMyAdmin\SqlParser\Components\Expression;
use PhpMyAdmin\SqlParser\Components\FunctionCall;
Expand Down Expand Up @@ -233,7 +234,7 @@ class SelectStatement extends Statement
/**
* Expressions that are being selected by this statement.
*
* @var Expression[]
* @var (CaseExpression|Expression)[]
*/
public array $expr = [];

Expand Down
31 changes: 18 additions & 13 deletions src/TokensList.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use ArrayAccess;

use function array_splice;
use function count;
use function in_array;
use function is_array;
Expand Down Expand Up @@ -179,53 +180,57 @@ public function getNextOfTypeAndFlag(TokenType $type, int $flag): Token|null
}

/**
* Sets an value inside the container.
* Sets a Token inside the list of tokens.
* When defined, offset must be positive otherwise the offset is ignored.
* If the offset is not defined (like in array_push) or if it is greater than the number of Tokens already stored,
* the Token is appended to the list of tokens.
*
* @param int|null $offset the offset to be set
* @param int|null $offset the offset to be set. Must be positive otherwise, nothing will be stored.
* @param Token $value the token to be saved
*/
public function offsetSet(mixed $offset, mixed $value): void
{
if ($offset === null) {
if ($offset === null || $offset >= $this->count) {
$this->tokens[$this->count++] = $value;
} else {
} elseif ($offset >= 0) {
$this->tokens[$offset] = $value;
}
}

/**
* Gets a value from the container.
* Gets a Token from the list of tokens.
* If the offset is negative or above the number of tokens set in the list, will return null.
*
* @param int $offset the offset to be returned
*/
public function offsetGet(mixed $offset): Token|null
{
return $offset < $this->count ? $this->tokens[$offset] : null;
return $this->offsetExists($offset) ? $this->tokens[$offset] : null;
}

/**
* Checks if an offset was previously set.
* If the offset is negative or above the number of tokens set in the list, will return false.
*
* @param int $offset the offset to be checked
*/
public function offsetExists(mixed $offset): bool
{
return $offset < $this->count;
return $offset >= 0 && $offset < $this->count;
}

/**
* Unsets the value of an offset.
* Unsets the value of an offset, if the offset exists.
*
* @param int $offset the offset to be unset
*/
public function offsetUnset(mixed $offset): void
{
unset($this->tokens[$offset]);
--$this->count;
for ($i = $offset; $i < $this->count; ++$i) {
$this->tokens[$i] = $this->tokens[$i + 1];
if (! $this->offsetExists($offset)) {
return;
}

unset($this->tokens[$this->count]);
array_splice($this->tokens, $offset, 1);
--$this->count;
}
}
30 changes: 27 additions & 3 deletions tests/Lexer/TokensListTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,17 +140,41 @@ public function testArrayAccess(): void
// offsetSet($offset, $value)
$list[2] = $this->tokens[2];

// offsetSet($offset, $value) with overflowed offset
$list[$list->count] = $this->tokens[1];
$this->assertSame($list[$list->count - 1], $this->tokens[1]);
$this->assertSame($list->count, count($this->tokens) + 1);

// offsetGet($offset) with negative offset
$this->assertNull($list[-1]);

// offsetGet($offset) with overflow offset
$this->assertNull($list[$list->count]);

// offsetGet($offset)
for ($i = 0, $count = count($this->tokens); $i < $count; ++$i) {
$this->assertEquals($this->tokens[$i], $list[$i]);
$this->assertSame($this->tokens[$i], $list[$i]);
}

// offsetExists($offset)
$this->assertArrayHasKey(2, $list);
$this->assertArrayNotHasKey(13, $list);
$this->assertArrayNotHasKey(14, $list);
$this->assertArrayNotHasKey(-8, $list);

// offsetUnset($offset)
$currentCountTokens = $list->count;
unset($list[2]);
$this->assertEquals($this->tokens[3], $list[2]);
$newCountTokens = $list->count;
$this->assertSame($this->tokens[3], $list[2]);
$this->assertSame($currentCountTokens - 1, $newCountTokens);

// offsetUnset($offset) with invalid offset (negative or overflowed)
$currentListTokens = $list->tokens;
unset($list[-1]);
$this->assertSame($currentListTokens, $list->tokens);
$this->assertSame($newCountTokens, $list->count); // No unset actually performed.
unset($list[999]);
$this->assertSame($currentListTokens, $list->tokens);
$this->assertSame($newCountTokens, $list->count); // No unset actually performed.
}
}
2 changes: 2 additions & 0 deletions tests/Parser/AlterStatementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public static function alterProvider(): array
['parser/parseAlterErr4'],
['parser/parseAlterTableRenameIndex1'],
['parser/parseAlterTableRenameIndex2'],
['parser/parseAlterTableRenameKey1'],
['parser/parseAlterTableRenameKey2'],
['parser/parseAlterTablePartitionByRange1'],
['parser/parseAlterTablePartitionByRange2'],
['parser/parseAlterTableCoalescePartition'],
Expand Down
1 change: 1 addition & 0 deletions tests/Parser/LoadStatementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public static function loadProvider(): array
['parser/parseLoad5'],
['parser/parseLoad6'],
['parser/parseLoad7'],
['parser/parseLoad8'],
['parser/parseLoadErr1'],
['parser/parseLoadErr2'],
['parser/parseLoadErr3'],
Expand Down
18 changes: 7 additions & 11 deletions tests/data/bugs/gh317.out
Original file line number Diff line number Diff line change
Expand Up @@ -241,19 +241,15 @@
"@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray",
"options": {
"1": "ADD",
"2": "KEY"
"2": {
"name": "KEY",
"equals": false,
"expr": "`IDX_REPAIR`",
"value": "IDX_REPAIR"
}
}
},
"field": {
"@type": "PhpMyAdmin\\SqlParser\\Components\\Expression",
"database": null,
"table": null,
"column": "IDX_REPAIR",
"expr": "`IDX_REPAIR`",
"alias": null,
"function": null,
"subquery": null
},
"field": null,
"partitions": null,
"unknown": [
{
Expand Down
2 changes: 1 addition & 1 deletion tests/data/lexer/lexNumber.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
SELECT 12, 34, 5.67, 0x89, -10, --11, +12, .15, 0xFFa, 0xfFA, +0xfFA, -0xFFa, -0xfFA, 1e-10, 1e10, .5e10, b'10';
-- invalid numbers
SELECT 12ex10, b'15', 0XFfA, -0XFfA, +0XFfA;
SELECT 12ex10, b'15', 0XFfA, -0XFfA, +0XFfA, .e4;
Loading

0 comments on commit 1e1693e

Please sign in to comment.