summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Components/UnionKeyword.php41
-rw-r--r--src/Parser.php18
-rw-r--r--src/Statement.php5
-rw-r--r--src/Statements/SelectStatement.php3
-rw-r--r--src/Utils/Query.php11
-rw-r--r--tests/Utils/QueryTest.php15
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()