Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions src/Components/Limit.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,6 @@ public static function parse(Parser $parser, TokensList $list, array $options =
*/
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;
}
}
262 changes: 247 additions & 15 deletions src/Statements/DeleteStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -24,6 +29,21 @@
* [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
Expand All @@ -45,29 +65,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.
Expand Down Expand Up @@ -96,4 +112,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;
}
}
Loading