diff options
-rw-r--r-- | src/Components/UnionKeyword.php | 41 | ||||
-rw-r--r-- | src/Parser.php | 18 | ||||
-rw-r--r-- | src/Statement.php | 5 | ||||
-rw-r--r-- | src/Statements/SelectStatement.php | 3 | ||||
-rw-r--r-- | src/Utils/Query.php | 11 | ||||
-rw-r--r-- | tests/Utils/QueryTest.php | 15 |
6 files changed, 86 insertions, 7 deletions
diff --git a/src/Components/UnionKeyword.php b/src/Components/UnionKeyword.php new file mode 100644 index 0000000..5a247bc --- /dev/null +++ b/src/Components/UnionKeyword.php @@ -0,0 +1,41 @@ +<?php + +/** + * `UNION` keyword builder. + * + * @package SqlParser + * @subpackage Components + */ +namespace SqlParser\Components; + +use SqlParser\Component; +use SqlParser\Parser; +use SqlParser\Token; +use SqlParser\TokensList; + +/** + * `UNION` keyword builder. + * + * @category Keywords + * @package SqlParser + * @subpackage Components + * @author Dan Ungureanu <udan1107@gmail.com> + * @license http://opensource.org/licenses/GPL-2.0 GNU Public License + */ +class UnionKeyword extends Component +{ + + /** + * @param SelectStatement[] $component The component to be built. + * + * @return string + */ + public static function build($component) + { + $ret = array(); + foreach ($component as $c) { + $ret[] = $c->build(); + } + return implode(" UNION ", $ret); + } +} diff --git a/src/Parser.php b/src/Parser.php index 249291c..31a6244 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -114,6 +114,12 @@ namespace SqlParser { 'field' => 'options', ), + // This is used only for building. + 'UNION' => array( + 'class' => 'SqlParser\\Components\\UnionKeyword', + 'field' => 'union', + ), + 'ALTER' => array( 'class' => 'SqlParser\\Components\\Expression', 'field' => 'table', @@ -425,6 +431,18 @@ namespace SqlParser { * @var SelectStatement $lastStatement */ $lastStatement->union[] = $statement; + + // if there are no no delimiting brackets, the `ORDER` and + // `LIMIT` keywords actually belong to the first statement. + $lastStatement->order = $statement->order; + $lastStatement->limit = $statement->limit; + $statement->order = null; + $statement->limit = null; + + // The statement actually ends where the last statement in + // union ends. + $lastStatement->last = $statement->last; + $inUnion = false; continue; } diff --git a/src/Statement.php b/src/Statement.php index 07d73d6..17a6002 100644 --- a/src/Statement.php +++ b/src/Statement.php @@ -122,11 +122,6 @@ abstract class Statement */ $type = $clause[1]; - // Checking if there is any parser (builder) for this clause. - if (empty(Parser::$KEYWORD_PARSERS[$name])) { - continue; - } - /** * The builder (parser) of this clause. * @var string $class diff --git a/src/Statements/SelectStatement.php b/src/Statements/SelectStatement.php index 954c220..a19bd8e 100644 --- a/src/Statements/SelectStatement.php +++ b/src/Statements/SelectStatement.php @@ -99,6 +99,9 @@ class SelectStatement extends Statement 'PROCEDURE' => array('PROCEDURE', 3), 'INTO' => array('INTO', 3), 'UNION' => array('UNION', 3), + // These are available only when `UNION` is present. + // 'ORDER BY' => array('ORDER BY', 3), + // 'LIMIT' => array('LIMIT', 3), ); /** diff --git a/src/Utils/Query.php b/src/Utils/Query.php index bec402a..1f887ab 100644 --- a/src/Utils/Query.php +++ b/src/Utils/Query.php @@ -533,6 +533,14 @@ class Query */ $clauses = array_flip(array_keys($statement::$CLAUSES)); + // This is a cheap fix for `SELECT` statements that contain `UNION`. + // Replacing the `ORDER BY` or `LIMIT` clauses should replace the last + // clause. + if (!empty($statement->union)) { + $clauses['ORDER BY'] = count($clauses) + 1; + $clauses['LIMIT'] = count($clauses) + 2; + } + /** * Lexer used for lexing the clause. * @var Lexer $lexer @@ -552,10 +560,9 @@ class Query $clauseIdx = $clauses[$clauseType]; $firstClauseIdx = $clauseIdx; - $lastClauseIdx = $clauseIdx + 1; - // Determining the behaviour of this function. + // Determining the behavior of this function. if ($type === -1) { $firstClauseIdx = -1; // Something small enough. $lastClauseIdx = $clauseIdx - 1; diff --git a/tests/Utils/QueryTest.php b/tests/Utils/QueryTest.php index c3a2f28..8dd2323 100644 --- a/tests/Utils/QueryTest.php +++ b/tests/Utils/QueryTest.php @@ -385,6 +385,21 @@ class QueryTest extends TestCase 'WHERE film_id > 0' ) ); + + $parser = new Parser( + 'select supplier.city, supplier.id from supplier ' + . 'union select customer.city, customer.id from customer' + ); + $this->assertEquals( + 'select supplier.city, supplier.id from supplier ' + . 'union select customer.city, customer.id from customer' + . ' ORDER BY city ', + Query::replaceClause( + $parser->statements[0], + $parser->list, + 'ORDER BY city' + ) + ); } public function testReplaceClauseOnlyKeyword() |