diff options
author | Dan Ungureanu <udan1107@gmail.com> | 2015-11-02 23:10:28 +0200 |
---|---|---|
committer | Dan Ungureanu <udan1107@gmail.com> | 2015-11-02 23:40:44 +0200 |
commit | 991fe545514e51bacaf58ad87358f984bce2c6f8 (patch) | |
tree | 61ae3ab1313f56e8d25c29ae66e27506a3abefbd /src | |
parent | 03eb61c873122d46f605d6de7a4aecc3de09ff9b (diff) | |
download | sql-parser-991fe545514e51bacaf58ad87358f984bce2c6f8.zip sql-parser-991fe545514e51bacaf58ad87358f984bce2c6f8.tar.gz sql-parser-991fe545514e51bacaf58ad87358f984bce2c6f8.tar.bz2 |
Fix the order of clauses in SELECT statements involing UNIONs.
Diffstat (limited to 'src')
-rw-r--r-- | src/Parser.php | 15 | ||||
-rw-r--r-- | src/Statement.php | 26 | ||||
-rw-r--r-- | src/Statements/SelectStatement.php | 21 | ||||
-rw-r--r-- | src/Utils/Query.php | 10 |
4 files changed, 61 insertions, 11 deletions
diff --git a/src/Parser.php b/src/Parser.php index 1277601..4646ed2 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -151,7 +151,7 @@ class Parser 'FROM' => array( 'class' => 'SqlParser\\Components\\ExpressionArray', 'field' => 'from', - 'options' => array('skipColumn' => true), + 'options' => array('skipColumn' => true, 'noBrackets' => true), ), 'GROUP BY' => array( 'class' => 'SqlParser\\Components\\OrderKeyword', @@ -298,6 +298,13 @@ class Parser public $statements = array(); /** + * The number of opened brackets. + * + * @var int + */ + public $brackets = 0; + + /** * Constructor. * * @param string|UtfString|TokensList $list The list of tokens to be parsed. @@ -381,6 +388,12 @@ class Parser continue; } + // Counting the brackets around statements. + if ($token->value === '(') { + ++$this->brackets; + continue; + } + // Statements can start with keywords only. // Comments, whitespaces, etc. are ignored. if ($token->type !== Token::TYPE_KEYWORD) { diff --git a/src/Statement.php b/src/Statement.php index b15dc3d..a9d4dc8 100644 --- a/src/Statement.php +++ b/src/Statement.php @@ -122,7 +122,14 @@ abstract class Statement */ $built = array(); - foreach (static::$CLAUSES as $clause) { + /** + * Statement's clauses. + * + * @var array + */ + $clauses = $this->getClauses(); + + foreach ($clauses as $clause) { /** * The name of the clause. * @@ -224,6 +231,13 @@ abstract class Statement break; } + // Checking if this closing bracket is the pair for a bracket + // outside the statement. + if (($token->value === ')') && ($parser->brackets > 0)) { + --$parser->brackets; + continue; + } + // Only keywords are relevant here. Other parts of the query are // processed in the functions below. if ($token->type !== Token::TYPE_KEYWORD) { @@ -364,6 +378,16 @@ abstract class Statement } /** + * Gets the clauses of this statement. + * + * @return array + */ + public function getClauses() + { + return static::$CLAUSES; + } + + /** * Builds the string representation of this statement. * * @see static::build diff --git a/src/Statements/SelectStatement.php b/src/Statements/SelectStatement.php index add3b8b..4bcbf2d 100644 --- a/src/Statements/SelectStatement.php +++ b/src/Statements/SelectStatement.php @@ -195,4 +195,25 @@ class SelectStatement extends Statement * @var SelectStatement[] */ public $union = array(); + + /** + * Gets the clauses of this statement. + * + * @return array + */ + public function getClauses() + { + // This is a cheap fix for `SELECT` statements that contain `UNION`. + // The `ORDER BY` and `LIMIT` clauses should be at the end of the + // statement. + if (!empty($this->union)) { + $clauses = static::$CLAUSES; + unset($clauses['ORDER BY']); + unset($clauses['LIMIT']); + $clauses['ORDER BY'] = array('ORDER BY', 3); + $clauses['LIMIT'] = array('LIMIT', 3); + return $clauses; + } + return static::$CLAUSES; + } } diff --git a/src/Utils/Query.php b/src/Utils/Query.php index ab2849b..d76e6bb 100644 --- a/src/Utils/Query.php +++ b/src/Utils/Query.php @@ -546,15 +546,7 @@ class Query * * @var array $clauses */ - $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 (($statement instanceof SelectStatement) && (!empty($statement->union))) { - $clauses['ORDER BY'] = count($clauses) + 1; - $clauses['LIMIT'] = count($clauses) + 2; - } + $clauses = array_flip(array_keys($statement->getClauses())); /** * Lexer used for lexing the clause. |