diff --git a/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php b/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php index 93618e770..2b984b846 100644 --- a/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php +++ b/lib/Doctrine/ORM/Tools/Pagination/LimitSubqueryOutputWalker.php @@ -354,46 +354,39 @@ class LimitSubqueryOutputWalker extends SqlWalker /** * Generates new SQL for statements with an order by clause * - * @param array $sqlIdentifier - * @param string $innerSql - * @param string $sql - * @param OrderByClause $orderByClause + * @param array $sqlIdentifier + * @param string $innerSql + * @param string $sql + * @param OrderByClause $orderByClause * * @return string */ - private function preserveSqlOrdering(array $sqlIdentifier, $innerSql, $sql, $orderByClause) { + private function preserveSqlOrdering(array $sqlIdentifier, $innerSql, $sql, $orderByClause) + { // If the sql statement has an order by clause, we need to wrap it in a new select distinct // statement - if (!$orderByClause instanceof OrderByClause) { + if (! $orderByClause instanceof OrderByClause) { return $sql; } // Rebuild the order by clause to work in the scope of the new select statement /* @var array $orderBy an array of rebuilt order by items */ $orderBy = $this->rebuildOrderByClauseForOuterScope($orderByClause); - $orderByFields = str_replace([' DESC', ' ASC'], ['', ''], $orderBy); - $innerSqlIdentifier = []; + $innerSqlIdentifier = $sqlIdentifier; - foreach ($orderByFields as $k => $v) { - // remove fields that are selected by identifiers, + foreach ($orderBy as $field) { + $field = preg_replace('/((\S+)\s+(ASC|DESC)\s*,?)*/', '${2}', $field); + + // skip fields that are selected by identifiers, // if those are ordered by in the query - if (in_array($v, $sqlIdentifier)) { - unset($orderByFields[$k]); + if (in_array($field, $sqlIdentifier, true)) { + continue; } + $innerSqlIdentifier[] = $field; } - foreach ($sqlIdentifier as $k => $v) { - $innerSqlIdentifier[$k] = 'dctrn_result_inner.' . $v; - $sqlIdentifier[$k] = 'dctrn_result.' . $v; - } - - // add the - foreach ($orderByFields as $k => $v) { - $innerSqlIdentifier[$k] = 'dctrn_result_inner.' . $v; - } - - // Build the select distinct statement + // Build the innner select statement $sql = sprintf( 'SELECT DISTINCT %s FROM (%s) dctrn_result_inner ORDER BY %s', implode(', ', $innerSqlIdentifier), diff --git a/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php b/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php index 7e65ab7bc..463c413d2 100644 --- a/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/Pagination/LimitSubqueryOutputWalkerTest.php @@ -208,7 +208,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); $this->assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1 FROM Author a0_) dctrn_result ORDER BY (1 - 1000) * 1 DESC', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, (1 - 1000) * 1 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1 FROM Author a0_) dctrn_result_inner ORDER BY (1 - 1000) * 1 DESC) dctrn_result', $query->getSQL() ); } @@ -223,7 +223,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); $this->assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT a0_.id AS id_0, a0_.image AS image_1, a0_.image_height AS image_height_2, a0_.image_width AS image_width_3, a0_.image_alt_desc AS image_alt_desc_4, a0_.user_id AS user_id_5 FROM Avatar a0_) dctrn_result ORDER BY image_height_2 * image_width_3 DESC', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, image_height_2 * image_width_3 FROM (SELECT a0_.id AS id_0, a0_.image AS image_1, a0_.image_height AS image_height_2, a0_.image_width AS image_width_3, a0_.image_alt_desc AS image_alt_desc_4, a0_.user_id AS user_id_5 FROM Avatar a0_) dctrn_result_inner ORDER BY image_height_2 * image_width_3 DESC) dctrn_result', $query->getSQL() ); } @@ -238,7 +238,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); $this->assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT u0_.id AS id_0, a1_.image_height AS image_height_1, a1_.image_width AS image_width_2, a1_.user_id AS user_id_3 FROM User u0_ INNER JOIN Avatar a1_ ON u0_.id = a1_.user_id) dctrn_result ORDER BY image_height_1 * image_width_2 DESC', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, image_height_1 * image_width_2 FROM (SELECT u0_.id AS id_0, a1_.image_height AS image_height_1, a1_.image_width AS image_width_2, a1_.user_id AS user_id_3 FROM User u0_ INNER JOIN Avatar a1_ ON u0_.id = a1_.user_id) dctrn_result_inner ORDER BY image_height_1 * image_width_2 DESC) dctrn_result', $query->getSQL() ); } @@ -253,7 +253,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); $this->assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT u0_.id AS id_0, a1_.id AS id_1, a1_.image_alt_desc AS image_alt_desc_2, a1_.image_height AS image_height_3, a1_.image_width AS image_width_4, a1_.user_id AS user_id_5 FROM User u0_ INNER JOIN Avatar a1_ ON u0_.id = a1_.user_id) dctrn_result ORDER BY image_height_3 * image_width_4 DESC', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, image_height_3 * image_width_4 FROM (SELECT u0_.id AS id_0, a1_.id AS id_1, a1_.image_alt_desc AS image_alt_desc_2, a1_.image_height AS image_height_3, a1_.image_width AS image_width_4, a1_.user_id AS user_id_5 FROM User u0_ INNER JOIN Avatar a1_ ON u0_.id = a1_.user_id) dctrn_result_inner ORDER BY image_height_3 * image_width_4 DESC) dctrn_result', $query->getSQL() ); } @@ -285,7 +285,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); $this->assertEquals( - 'SELECT DISTINCT id_0 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, a0_.name AS name_2 FROM Author a0_) dctrn_result ORDER BY name_2 DESC', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, name_2 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, a0_.name AS name_2 FROM Author a0_) dctrn_result_inner ORDER BY name_2 DESC) dctrn_result', $query->getSQL() ); } @@ -300,7 +300,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); $this->assertSame( - 'SELECT DISTINCT id_0 FROM (SELECT a0_.id AS id_0, a0_.image AS image_1, a0_.image_height AS image_height_2, a0_.image_width AS image_width_3, a0_.image_alt_desc AS image_alt_desc_4, a0_.user_id AS user_id_5 FROM Avatar a0_) dctrn_result ORDER BY image_alt_desc_4 DESC', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, image_alt_desc_4 FROM (SELECT a0_.id AS id_0, a0_.image AS image_1, a0_.image_height AS image_height_2, a0_.image_width AS image_width_3, a0_.image_alt_desc AS image_alt_desc_4, a0_.user_id AS user_id_5 FROM Avatar a0_) dctrn_result_inner ORDER BY image_alt_desc_4 DESC) dctrn_result', $query->getSQL() ); } @@ -314,7 +314,7 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); $this->assertEquals( - 'SELECT DISTINCT id_0 FROM (SELECT b0_.id AS id_0, a1_.name AS name_1, b0_.author_id AS author_id_2, b0_.category_id AS category_id_3 FROM BlogPost b0_ INNER JOIN Author a1_ ON b0_.author_id = a1_.id) dctrn_result ORDER BY name_1 ASC', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, name_1 FROM (SELECT b0_.id AS id_0, a1_.name AS name_1, b0_.author_id AS author_id_2, b0_.category_id AS category_id_3 FROM BlogPost b0_ INNER JOIN Author a1_ ON b0_.author_id = a1_.id) dctrn_result_inner ORDER BY name_1 ASC) dctrn_result', $query->getSQL() ); } @@ -330,7 +330,7 @@ ORDER BY b.id DESC' $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); $this->assertEquals( - 'SELECT DISTINCT id_0 FROM (SELECT b0_.id AS id_0, b0_.author_id AS author_id_1, b0_.category_id AS category_id_2 FROM BlogPost b0_ WHERE ((SELECT COUNT(b1_.id) AS sclr_3 FROM BlogPost b1_) = 1)) dctrn_result ORDER BY id_0 DESC', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0 FROM (SELECT b0_.id AS id_0, b0_.author_id AS author_id_1, b0_.category_id AS category_id_2 FROM BlogPost b0_ WHERE ((SELECT COUNT(b1_.id) AS sclr_3 FROM BlogPost b1_) = 1)) dctrn_result_inner ORDER BY id_0 DESC) dctrn_result', $query->getSQL() ); } @@ -365,7 +365,7 @@ ORDER BY b.id DESC' $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); $this->assertEquals( - 'SELECT DISTINCT id_0 FROM (SELECT b0_.id AS id_0, b0_.name AS name_1 FROM Banner b0_) dctrn_result ORDER BY id_0 DESC', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0 FROM (SELECT b0_.id AS id_0, b0_.name AS name_1 FROM Banner b0_) dctrn_result_inner ORDER BY id_0 DESC) dctrn_result', $query->getSQL() ); } @@ -390,7 +390,7 @@ ORDER BY b.id DESC' $query->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, LimitSubqueryOutputWalker::class); $this->assertEquals( - 'SELECT DISTINCT id_0 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, (SELECT MIN(m1_.title) AS sclr_3 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS sclr_2 FROM Author a0_) dctrn_result ORDER BY sclr_2 DESC', + 'SELECT DISTINCT id_0 FROM (SELECT DISTINCT id_0, sclr_2 FROM (SELECT a0_.id AS id_0, a0_.name AS name_1, (SELECT MIN(m1_.title) AS sclr_3 FROM MyBlogPost m1_ WHERE m1_.author_id = a0_.id) AS sclr_2 FROM Author a0_) dctrn_result_inner ORDER BY sclr_2 DESC) dctrn_result', $query->getSQL() ); }