%PDF- %PDF-
Direktori : /var/www/projetos/admin.iigd.com.br/vendor/phpmyadmin/sql-parser/src/Statements/ |
Current File : /var/www/projetos/admin.iigd.com.br/vendor/phpmyadmin/sql-parser/src/Statements/WithStatement.php |
<?php /** * `WITH` statement. */ declare(strict_types=1); namespace PhpMyAdmin\SqlParser\Statements; use PhpMyAdmin\SqlParser\Components\Array2d; use PhpMyAdmin\SqlParser\Components\OptionsArray; use PhpMyAdmin\SqlParser\Components\WithKeyword; use PhpMyAdmin\SqlParser\Exceptions\ParserException; use PhpMyAdmin\SqlParser\Parser; use PhpMyAdmin\SqlParser\Statement; use PhpMyAdmin\SqlParser\Token; use PhpMyAdmin\SqlParser\TokensList; use PhpMyAdmin\SqlParser\Translator; use function array_slice; use function count; /** * `WITH` statement. * WITH [RECURSIVE] query_name [ (column_name [,...]) ] AS (SELECT ...) [, ...] */ final class WithStatement extends Statement { /** * Options for `WITH` statements and their slot ID. * * @var mixed[] */ public static $OPTIONS = ['RECURSIVE' => 1]; /** * The clauses of this statement, in order. * * @see Statement::$CLAUSES * * @var mixed[] */ public static $CLAUSES = [ 'WITH' => [ 'WITH', 2, ], // Used for options. '_OPTIONS' => [ '_OPTIONS', 1, ], 'AS' => [ 'AS', 2, ], ]; /** @var WithKeyword[] */ public $withers = []; /** * @param Parser $parser the instance that requests parsing * @param TokensList $list the list of tokens to be parsed */ public function parse(Parser $parser, TokensList $list) { ++$list->idx; // Skipping `WITH`. // parse any options if provided $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS); ++$list->idx; /** * The state of the parser. * * Below are the states of the parser. * * 0 ---------------- [ name ] -----------------> 1 * 1 -------------- [( columns )] AS ----------------> 2 * 2 ------------------ [ , ] --------------------> 0 * * @var int */ $state = 0; $wither = null; for (; $list->idx < $list->count; ++$list->idx) { /** * Token parsed at this moment. * * @var Token */ $token = $list->tokens[$list->idx]; // Skipping whitespaces and comments. if ($token->type === Token::TYPE_WHITESPACE || $token->type === Token::TYPE_COMMENT) { continue; } if ($token->type === Token::TYPE_NONE) { $wither = $token->value; $this->withers[$wither] = new WithKeyword($wither); $state = 1; continue; } if ($state === 1) { if ($token->value === '(') { $this->withers[$wither]->columns = Array2d::parse($parser, $list); continue; } if ($token->keyword === 'AS') { ++$list->idx; $state = 2; continue; } } elseif ($state === 2) { if ($token->value === '(') { ++$list->idx; $subList = $this->getSubTokenList($list); if ($subList instanceof ParserException) { $parser->errors[] = $subList; continue; } $subParser = new Parser($subList); if (count($subParser->errors)) { foreach ($subParser->errors as $error) { $parser->errors[] = $error; } } $this->withers[$wither]->statement = $subParser; continue; } // There's another WITH expression to parse, go back to state=0 if ($token->value === ',') { $list->idx++; $state = 0; continue; } // No more WITH expressions, we're done with this statement break; } } --$list->idx; } /** * {@inheritdoc} */ public function build() { $str = 'WITH '; foreach ($this->withers as $wither) { $str .= $str === 'WITH ' ? '' : ', '; $str .= WithKeyword::build($wither); } return $str; } /** * Get tokens within the WITH expression to use them in another parser * * @return ParserException|TokensList */ private function getSubTokenList(TokensList $list) { $idx = $list->idx; /** @var Token $token */ $token = $list->tokens[$list->idx]; $openParenthesis = 0; while ($list->idx < $list->count) { if ($token->value === '(') { ++$openParenthesis; } elseif ($token->value === ')') { if (--$openParenthesis === -1) { break; } } ++$list->idx; if (! isset($list->tokens[$list->idx])) { break; } $token = $list->tokens[$list->idx]; } // performance improvement: return the error to avoid a try/catch in the loop if ($list->idx === $list->count) { --$list->idx; return new ParserException( Translator::gettext('A closing bracket was expected.'), $token ); } $length = $list->idx - $idx; return new TokensList(array_slice($list->tokens, $idx, $length), $length); } }