diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index 0233e4c5e..4d097b5ff 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -1339,12 +1339,37 @@ class Parser */ public function OrderByItem() { - $type = 'ASC'; - // We need to check if we are in a ResultVariable or StateFieldPathExpression $glimpse = $this->_lexer->glimpse(); - $expr = ($glimpse['type'] != Lexer::T_DOT) ? $this->ResultVariable() : $this->SingleValuedPathExpression(); + switch (true) { + case ($glimpse['type'] === Lexer::T_DOT): + $expr = $this->SingleValuedPathExpression(); + break; + + case ($this->_isFunction()): + $this->_lexer->peek(); // "(" + + // SUM(u.id) + COUNT(u.id) + if ($this->_isMathOperator($this->_peekBeyondClosingParenthesis())) { + $expr = $this->ScalarExpression(); + break; + } + // COUNT(u.id) + if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) { + $expr = $this->AggregateExpression(); + break; + } + // IDENTITY(u) + $expr = $this->FunctionDeclaration(); + break; + + default: + $expr = $this->ResultVariable(); + break; + } + + $type = 'ASC'; $item = new AST\OrderByItem($expr); switch (true) { @@ -2166,10 +2191,10 @@ class Parser if (in_array($peek['value'], array("=", "<", "<=", "<>", ">", ">=", "!=")) || in_array($peek['type'], array(Lexer::T_NOT, Lexer::T_BETWEEN, Lexer::T_LIKE, Lexer::T_IN, Lexer::T_IS, Lexer::T_EXISTS)) || $this->_isMathOperator($peek)) { - $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression(); + $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression(); - return $condPrimary; - } + return $condPrimary; + } $this->match(Lexer::T_OPEN_PARENTHESIS); $condPrimary->conditionalExpression = $this->ConditionalExpression(); diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index b04d6e8d3..8426dc124 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -780,9 +780,18 @@ class SqlWalker implements TreeWalker public function walkOrderByItem($orderByItem) { $expr = $orderByItem->expression; - $sql = ($expr instanceof AST\PathExpression) - ? $this->walkPathExpression($expr) - : $this->walkResultVariable($this->_queryComponents[$expr]['token']['value']); + + switch (true) { + case ($expr instanceof AST\PathExpression): + case ($expr instanceof AST\AggregateExpression): + case ($expr instanceof AST\Functions\FunctionNode): + case ($expr instanceof AST\SimpleArithmeticExpression): + $sql = $expr->dispatch($this); + break; + default: + $sql = $this->walkResultVariable($this->_queryComponents[$expr]['token']['value']); + break; + } return $sql . ' ' . strtoupper($orderByItem->type); } diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index 5b750462c..e77fa6447 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -1571,6 +1571,54 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase "SELECT c0_.id AS id0, c0_.completed AS completed1, c0_.fixPrice AS fixPrice2, c1_.id AS id3, c1_.completed AS completed4, c1_.hoursWorked AS hoursWorked5, c1_.pricePerHour AS pricePerHour6, c1_.maxPrice AS maxPrice7, c0_.discr AS discr8, c1_.discr AS discr9 FROM company_contracts c0_, company_contracts c1_ WHERE (c0_.discr IN ('fix') AND c1_.discr IN ('flexible', 'flexultra'))" ); } + + /** + * @group DDC-775 + */ + public function testOrderByClauseSupportFunctions() + { + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY TRIM(u.name)', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ ORDER BY TRIM(c0_.name) ASC' + ); + + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY IDENTITY(u.email)', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ ORDER BY c0_.email_id ASC' + ); + + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY TRIM(IDENTITY(u.email))', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ ORDER BY TRIM(c0_.email_id) ASC' + ); + + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY SUM(u.id)', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ ORDER BY SUM(c0_.id) ASC' + ); + + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY SUM(u.id) + COUNT(u.email)', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ ORDER BY SUM(c0_.id) + COUNT(c0_.email_id) ASC' + ); + } + + /** + * @group DDC-775 + */ + public function testOrderByClauseSupportNullIfAndCoalesce() + { + $this->markTestIncomplete(); + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY NULLIF(u.name, u.username)', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ ORDER BY NULLIF(c0_.name, c0_.username) ASC' + ); + + $this->assertSqlGeneration( + 'SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY NULLIF(u.name, u.username)', + 'SELECT c0_.id AS id0, c0_.status AS status1, c0_.username AS username2, c0_.name AS name3 FROM cms_users c0_ ORDER BY COALESCE(NULLIF(u.name, \'\'), u.username) ASC' + ); + } }