diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 3c4fc8ed1..3dea8de4b 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -1093,6 +1093,10 @@ class SqlWalker implements TreeWalker $this->orderedColumnsMap[$sql] = $type; + if ($expr instanceof AST\Subselect) { + return '(' . $sql . ') ' . $type; + } + return $sql . ' ' . $type; } diff --git a/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php b/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php index efd8a7c2c..eea2e8375 100644 --- a/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/PaginationTest.php @@ -669,6 +669,28 @@ class PaginationTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertCount(9, $paginator); } + /** + * @dataProvider useOutputWalkersAndFetchJoinCollection + */ + public function testPaginationWithSubSelectOrderByExpression($useOutputWalker, $fetchJoinCollection) + { + $query = $this->_em->createQuery( + "SELECT u, + ( + SELECT MAX(a.version) + FROM Doctrine\\Tests\\Models\\CMS\\CmsArticle a + WHERE a.user = u + ) AS HIDDEN max_version + FROM Doctrine\\Tests\\Models\\CMS\\CmsUser u + ORDER BY max_version DESC" + ); + + $paginator = new Paginator($query, $fetchJoinCollection); + $paginator->setUseOutputWalkers($useOutputWalker); + + $this->assertCount(9, $paginator->getIterator()); + } + public function populate() { $groups = array(); diff --git a/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php b/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php index 205be7d1f..40fe1575a 100644 --- a/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php @@ -350,5 +350,80 @@ ORDER BY b.id DESC' $query->getSQL() ); } + + /** + * Tests order by on a subselect expression (mysql). + */ + public function testLimitSubqueryOrderBySubSelectOrderByExpression() + { + $this->entityManager->getConnection()->setDatabasePlatform(new MysqlPlatform()); + + $query = $this->entityManager->createQuery( + 'SELECT a, + ( + SELECT MIN(bp.title) + FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost bp + WHERE bp.author = a + ) AS HIDDEN first_blog_post + FROM Doctrine\Tests\ORM\Tools\Pagination\Author a + ORDER BY first_blog_post DESC' + ); + $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker'); + + $this->assertEquals( + 'SELECT DISTINCT id_0 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, (SELECT MIN(m1_.title) AS dctrn__1 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS sclr_2 FROM Author a0_) dctrn_result ORDER BY sclr_2 DESC', + $query->getSQL() + ); + } + + /** + * Tests order by on a subselect expression invoking RowNumberOverFunction (postgres). + */ + public function testLimitSubqueryOrderBySubSelectOrderByExpressionPg() + { + $this->entityManager->getConnection()->setDatabasePlatform(new PostgreSqlPlatform()); + + $query = $this->entityManager->createQuery( + 'SELECT a, + ( + SELECT MIN(bp.title) + FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost bp + WHERE bp.author = a + ) AS HIDDEN first_blog_post + FROM Doctrine\Tests\ORM\Tools\Pagination\Author a + ORDER BY first_blog_post DESC' + ); + $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker'); + + $this->assertEquals( + 'SELECT DISTINCT id_0, MIN(sclr_3) AS dctrn_minrownum FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, (SELECT MIN(m1_.title) AS dctrn__1 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS sclr_2, ROW_NUMBER() OVER(ORDER BY (SELECT MIN(m1_.title) AS dctrn__2 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) DESC) AS sclr_3 FROM Author a0_) dctrn_result GROUP BY id_0 ORDER BY dctrn_minrownum ASC', + $query->getSQL() + ); + } + + /** + * Tests order by on a subselect expression invoking RowNumberOverFunction (oracle). + */ + public function testLimitSubqueryOrderBySubSelectOrderByExpressionOracle() + { + $this->entityManager->getConnection()->setDatabasePlatform(new OraclePlatform()); + + $query = $this->entityManager->createQuery( + 'SELECT a, + ( + SELECT MIN(bp.title) + FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost bp + WHERE bp.author = a + ) AS HIDDEN first_blog_post + FROM Doctrine\Tests\ORM\Tools\Pagination\Author a + ORDER BY first_blog_post DESC' + ); + $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker'); + + $this->assertEquals( + 'SELECT DISTINCT ID_0, MIN(SCLR_3) AS dctrn_minrownum FROM (SELECT a0_.id AS ID_0, a0_.name AS NAME_1, (SELECT MIN(m1_.title) AS dctrn__1 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS SCLR_2, ROW_NUMBER() OVER(ORDER BY (SELECT MIN(m1_.title) AS dctrn__2 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) DESC) AS SCLR_3 FROM Author a0_) dctrn_result GROUP BY ID_0 ORDER BY dctrn_minrownum ASC', + $query->getSQL() + ); + } }