Skip to content

Commit

Permalink
Optimize ExpressionAtom and checking inside parentheses
Browse files Browse the repository at this point in the history
Most of the `matches()` calls there just repeated previous checks
  • Loading branch information
sad-spirit committed Jan 11, 2025
1 parent 9fa61d3 commit 562f0f0
Showing 1 changed file with 79 additions and 62 deletions.
141 changes: 79 additions & 62 deletions src/sad_spirit/pg_builder/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -362,58 +362,65 @@ private function checkContentsOfParentheses(int $lookIdx = 0): ?string

do {
$token = $this->stream->look(++$lookIdx);
if (
(TokenType::COLON_EQUALS === $token->getType() || TokenType::EQUALS_GREATER == $token->getType())
&& 1 === \count($openParens) && !$selectLevel
) {
return self::PARENTHESES_ARGS;
}
if (!$token->matches(TokenType::SPECIAL_CHAR)) {
if ($token instanceof tokens\EOFToken) {
break;
} elseif (!$token instanceof tokens\StringToken) {
continue;
}
switch ($token->getValue()) {
case '[':
$lookIdx = $this->skipParentheses($lookIdx, true) - 1;
break;

case '(':
$openParens[] = $lookIdx;
break;
switch ($token->getType()) {
case TokenType::SPECIAL_CHAR:
switch ($token->getValue()) {
case '[':
$lookIdx = $this->skipParentheses($lookIdx, true) - 1;
break;

case ',':
if (1 === \count($openParens) && !$selectLevel) {
return self::PARENTHESES_ROW;
case '(':
$openParens[] = $lookIdx;
break;

case ',':
if (1 === \count($openParens) && !$selectLevel) {
return self::PARENTHESES_ROW;
}
break;

case ')':
if (1 < \count($openParens) && $selectLevel === \count($openParens)) {
if (
$this->stream->look($lookIdx + 1)
->matchesAnyKeyword(
Keyword::UNION,
Keyword::INTERSECT,
Keyword::EXCEPT,
Keyword::ORDER,
Keyword::LIMIT,
Keyword::OFFSET,
Keyword::FOR /* ...update */,
Keyword::FETCH /* SQL:2008 limit */
)
|| $this->stream->look($lookIdx + 1)
->matches(TokenType::SPECIAL_CHAR, ')')
) {
// this addresses stuff like ((select 1) order by 1)
$selectLevel--;
} else {
$selectLevel = false;
}
}
\array_pop($openParens);
}
break;

case ')':
if (1 < \count($openParens) && $selectLevel === \count($openParens)) {
if (
$this->stream->look($lookIdx + 1)
->matchesAnyKeyword(
Keyword::UNION,
Keyword::INTERSECT,
Keyword::EXCEPT,
Keyword::ORDER,
Keyword::LIMIT,
Keyword::OFFSET,
Keyword::FOR /* ...update */,
Keyword::FETCH /* SQL:2008 limit */
)
|| $this->stream->look($lookIdx + 1)
->matches(TokenType::SPECIAL_CHAR, ')')
) {
// this addresses stuff like ((select 1) order by 1)
$selectLevel--;
} else {
$selectLevel = false;
}
case TokenType::COLON_EQUALS:
case TokenType::EQUALS_GREATER:
if (1 === \count($openParens) && !$selectLevel) {
return self::PARENTHESES_ARGS;
}
\array_pop($openParens);
}
} while (!empty($openParens) && !$token->matches(TokenType::EOF));
} while ([] !== $openParens);

if (!empty($openParens)) {
if ([] !== $openParens) {
$token = $this->stream->look(\array_shift($openParens));
throw exceptions\SyntaxException::atPosition(
"Unbalanced '('",
Expand Down Expand Up @@ -2458,31 +2465,41 @@ protected function ExpressionAtom(): nodes\ScalarExpression
{
switch ($keyword = $this->stream->matchesAnyKeyword(...self::ATOM_KEYWORDS)) {
case null:
$token = $this->stream->getCurrent();
if (0 === ($token->getType()->value & self::ATOM_SPECIAL_TYPES)) {
$token = $this->stream->getCurrent();
$tokenType = $token->getType();
if (0 === ($tokenType->value & self::ATOM_SPECIAL_TYPES)) {
break;
}
if ($token->matches(TokenType::SPECIAL_CHAR, '(')) {
switch ($this->checkContentsOfParentheses()) {
case self::PARENTHESES_ROW:
return $this->RowConstructor();

case self::PARENTHESES_SELECT:
$atom = new nodes\expressions\SubselectExpression($this->SelectWithParentheses());
switch ($tokenType) {
case TokenType::SPECIAL_CHAR:
if ('(' !== $token->getValue()) {
break;
}
switch ($this->checkContentsOfParentheses()) {
case self::PARENTHESES_ROW:
return $this->RowConstructor();

case self::PARENTHESES_SELECT:
$atom = new nodes\expressions\SubselectExpression($this->SelectWithParentheses());
break;

case self::PARENTHESES_EXPRESSION:
default:
$this->stream->next();
$atom = $this->Expression();
$this->stream->expect(TokenType::SPECIAL_CHAR, ')');
}
break;

case self::PARENTHESES_EXPRESSION:
default:
$this->stream->next();
$atom = $this->Expression();
$this->stream->expect(TokenType::SPECIAL_CHAR, ')');
}

} elseif ($token->matches(TokenType::PARAMETER)) {
$atom = nodes\expressions\Parameter::createFromToken($this->stream->next());
case TokenType::POSITIONAL_PARAM:
case TokenType::NAMED_PARAM:
$atom = nodes\expressions\Parameter::createFromToken($this->stream->next());
break;

} elseif ($token->matches(TokenType::LITERAL)) {
return nodes\expressions\Constant::createFromToken($this->stream->next());
default:
if ($token->matches(TokenType::LITERAL)) {
return nodes\expressions\Constant::createFromToken($this->stream->next());
}
}
break;

Expand Down

0 comments on commit 562f0f0

Please sign in to comment.