diff options
author | Michal Čihař <michal@cihar.com> | 2016-10-03 15:59:56 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-03 15:59:56 +0200 |
commit | 29a9dc198900877e63df6e0b33e884b6c3507b27 (patch) | |
tree | 1b8fe78e2906b70a3cd33abe5f57810a680b04ad /src | |
parent | 1b72bd39ba90580579b86b5f3bbd8f6815f10096 (diff) | |
parent | 98679cb7ed977d2b0d6cfa4b27c7964d41dc5c44 (diff) | |
download | sql-parser-29a9dc198900877e63df6e0b33e884b6c3507b27.zip sql-parser-29a9dc198900877e63df6e0b33e884b6c3507b27.tar.gz sql-parser-29a9dc198900877e63df6e0b33e884b6c3507b27.tar.bz2 |
Merge pull request #87 from devenbansod/delete_statement
Implement parsing and building for Delete Statement
Diffstat (limited to 'src')
-rw-r--r-- | src/Components/Limit.php | 6 | ||||
-rw-r--r-- | src/Statements/DeleteStatement.php | 262 |
2 files changed, 248 insertions, 20 deletions
diff --git a/src/Components/Limit.php b/src/Components/Limit.php index da4f7f7..13a1127 100644 --- a/src/Components/Limit.php +++ b/src/Components/Limit.php @@ -126,10 +126,6 @@ class Limit extends Component */ public static function build($component, array $options = array()) { - if (empty($component->offset)) { - return (string) $component->rowCount; - } else { - return $component->offset . ', ' . $component->rowCount; - } + return $component->offset . ', ' . $component->rowCount; } } diff --git a/src/Statements/DeleteStatement.php b/src/Statements/DeleteStatement.php index 0788ad2..394c0f4 100644 --- a/src/Statements/DeleteStatement.php +++ b/src/Statements/DeleteStatement.php @@ -9,11 +9,16 @@ namespace SqlParser\Statements; use SqlParser\Statement; +use SqlParser\Parser; +use SqlParser\Token; +use SqlParser\TokensList; use SqlParser\Components\ArrayObj; use SqlParser\Components\Expression; +use SqlParser\Components\ExpressionArray; use SqlParser\Components\Limit; use SqlParser\Components\OrderKeyword; use SqlParser\Components\Condition; +use SqlParser\Components\OptionsArray; /** * `DELETE` statement. @@ -24,6 +29,21 @@ use SqlParser\Components\Condition; * [ORDER BY ...] * [LIMIT row_count] * + * Multi-table syntax + * + * DELETE [LOW_PRIORITY] [QUICK] [IGNORE] + * tbl_name[.*] [, tbl_name[.*]] ... + * FROM table_references + * [WHERE where_condition] + * + * OR + * + * DELETE [LOW_PRIORITY] [QUICK] [IGNORE] + * FROM tbl_name[.*] [, tbl_name[.*]] ... + * USING table_references + * [WHERE where_condition] + * + * * @category Statements * @package SqlParser * @subpackage Statements @@ -44,29 +64,25 @@ class DeleteStatement extends Statement ); /** - * The clauses of this statement, in order. + * Table(s) used as sources for this statement. * - * @see Statement::$CLAUSES + * @var Expression[] + */ + public $from; + + /** + * Tables used as sources for this statement * - * @var array + * @var Expression[] */ - public static $CLAUSES = array( - 'DELETE' => array('DELETE', 2), - // Used for options. - '_OPTIONS' => array('_OPTIONS', 1), - 'FROM' => array('FROM', 3), - 'PARTITION' => array('PARTITION', 3), - 'WHERE' => array('WHERE', 3), - 'ORDER BY' => array('ORDER BY', 3), - 'LIMIT' => array('LIMIT', 3), - ); + public $using; /** - * Tables used as sources for this statement. + * Columns used in this statement * * @var Expression[] */ - public $from; + public $columns; /** * Partitions used as source for this statement. @@ -95,4 +111,220 @@ class DeleteStatement extends Statement * @var Limit */ public $limit; + + + /** + * @return string + */ + public function build() + { + $ret = 'DELETE ' . OptionsArray::build($this->options); + + if ($this->columns != NULL && count($this->columns) > 0) { + $ret .= ' ' . ExpressionArray::build($this->columns); + } + if ($this->from != NULL && count($this->from) > 0) { + $ret .= ' FROM ' . ExpressionArray::build($this->from); + } + if ($this->using != NULL && count($this->using) > 0) { + $ret .= ' USING ' . ExpressionArray::build($this->using); + } + if ($this->where != NULL && count($this->where) > 0) { + $ret .= ' WHERE ' . Condition::build($this->where); + } + if ($this->order != NULL && count($this->order) > 0) { + $ret .= ' ORDER BY ' . ExpressionArray::build($this->order); + } + if ($this->limit != NULL && count($this->limit) > 0) { + $ret .= ' LIMIT ' . Limit::build($this->limit); + } + + return $ret; + + } + + + /** + * @param Parser $parser The instance that requests parsing. + * @param TokensList $list The list of tokens to be parsed. + * + * @return void + */ + public function parse(Parser $parser, TokensList $list) + { + ++$list->idx; // Skipping `DELETE`. + + // 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 ---------------------------------[ FROM ]----------------------------------> 2 + * 0 ------------------------------[ table[.*] ]--------------------------------> 1 + * 1 ---------------------------------[ FROM ]----------------------------------> 2 + * 2 --------------------------------[ USING ]----------------------------------> 3 + * 2 --------------------------------[ WHERE ]----------------------------------> 4 + * 2 --------------------------------[ ORDER ]----------------------------------> 5 + * 2 --------------------------------[ LIMIT ]----------------------------------> 6 + * + * @var int $state + */ + $state = 0; + + /** + * If the query is multi-table or not + * + * @var bool $multiTable + */ + $multiTable = false; + + for (; $list->idx < $list->count; ++$list->idx) { + /** + * Token parsed at this moment. + * + * @var Token $token + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === Token::TYPE_DELIMITER) { + break; + } + + if ($state === 0) { + if ($token->type === Token::TYPE_KEYWORD + && $token->value !== 'FROM' + ) { + $parser->error(__('Unexpected keyword.'), $token); + break; + } elseif ($token->type === Token::TYPE_KEYWORD + && $token->value === 'FROM' + ) { + ++$list->idx; // Skip 'FROM' + $this->from = ExpressionArray::parse($parser, $list); + $state = 2; + } else { + $this->columns = ExpressionArray::parse($parser, $list); + $state = 1; + } + } elseif ($state === 1) { + if ($token->type === Token::TYPE_KEYWORD + && $token->value !== 'FROM' + ) { + $parser->error(__('Unexpected keyword.'), $token); + break; + } elseif ($token->type === Token::TYPE_KEYWORD + && $token->value === 'FROM' + ) { + ++$list->idx; // Skip 'FROM' + $this->from = ExpressionArray::parse($parser, $list); + $state = 2; + } else { + $parser->error(__('Unexpected token.'), $token); + break; + } + } elseif ($state === 2) { + if ($token->type === Token::TYPE_KEYWORD + && $token->value === 'USING' + ) { + ++$list->idx; // Skip 'USING' + $this->using = ExpressionArray::parse($parser, $list); + $state = 3; + + $multiTable = true; + } elseif ($token->type === Token::TYPE_KEYWORD + && $token->value === 'WHERE' + ) { + ++$list->idx; // Skip 'WHERE' + $this->where = Condition::parse($parser, $list); + $state = 4; + } elseif ($token->type === Token::TYPE_KEYWORD + && $token->value === 'ORDER BY' + ) { + ++$list->idx; // Skip 'ORDER BY' + $this->order = OrderKeyword::parse($parser, $list); + $state = 5; + } elseif ($token->type === Token::TYPE_KEYWORD + && $token->value === 'LIMIT' + ) { + ++$list->idx; // Skip 'LIMIT' + $this->limit = Limit::parse($parser, $list); + $state = 6; + } elseif ($token->type === Token::TYPE_KEYWORD) { + $parser->error(__('Unexpected keyword.'), $token); + break; + } + } elseif ($state === 3) { + if ($token->type === Token::TYPE_KEYWORD + && $token->value === 'WHERE' + ) { + ++$list->idx; // Skip 'WHERE' + $this->where = Condition::parse($parser, $list); + $state = 4; + } elseif ($token->type === Token::TYPE_KEYWORD) { + $parser->error(__('Unexpected keyword.'), $token); + break; + } else { + $parser->error(__('Unexpected token.'), $token); + break; + } + } elseif ($state === 4) { + if ($multiTable === true + && $token->type === Token::TYPE_KEYWORD + ) { + $parser->error( + __('This type of clause is not valid in Multi-table queries.'), + $token + ); + break; + } + + if ($token->type === Token::TYPE_KEYWORD + && $token->value === 'ORDER BY' + ) { + ++$list->idx; // Skip 'ORDER BY' + $this->order = OrderKeyword::parse($parser, $list); + $state = 5; + } elseif ($token->type === Token::TYPE_KEYWORD + && $token->value === 'LIMIT' + ) { + ++$list->idx; // Skip 'LIMIT' + $this->limit = Limit::parse($parser, $list); + $state = 6; + } elseif ($token->type === Token::TYPE_KEYWORD) { + $parser->error(__('Unexpected keyword.'), $token); + break; + } + } elseif ($state === 5) { + if ($token->type === Token::TYPE_KEYWORD + && $token->value === 'LIMIT' + ) { + ++$list->idx; // Skip 'LIMIT' + $this->limit = Limit::parse($parser, $list); + $state = 6; + } elseif ($token->type === Token::TYPE_KEYWORD) { + $parser->error(__('Unexpected keyword.'), $token); + break; + } + } + } + + if ($state >= 2) { + foreach ($this->from as $from_expr) { + $from_expr->database = $from_expr->table; + $from_expr->table = $from_expr->column; + $from_expr->column = null; + } + } + + --$list->idx; + } } |