1
0
mirror of synced 2024-12-13 22:56:04 +03:00

The distinct query should replicate the fields in order by clause and the order by clause itself from inner query

This fixes DDC-1958
This commit is contained in:
Miha Vrhovnik 2012-09-18 13:56:32 +02:00
parent 4e04daaed4
commit c7a75f477f
4 changed files with 82 additions and 3 deletions

View File

@ -15,6 +15,7 @@ namespace Doctrine\ORM\Tools\Pagination;
use Doctrine\ORM\Query\SqlWalker; use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\AST\SelectStatement; use Doctrine\ORM\Query\AST\SelectStatement;
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
/** /**
* Wrap the query in order to select root entity IDs for pagination * Wrap the query in order to select root entity IDs for pagination
@ -132,8 +133,44 @@ class LimitSubqueryOutputWalker extends SqlWalker
} }
// Build the counter query // Build the counter query
if ($this->platform instanceof PostgreSqlPlatform) {
//http://www.doctrine-project.org/jira/browse/DDC-1958
// For every order by, find out the SQL alias by inspecting the ResultSetMapping
$sqlOrderColumns = array();
$orderBy = array();
if (isset($AST->orderByClause)){
foreach ($AST->orderByClause->orderByItems as $item) {
$possibleAliases = array_keys($this->rsm->fieldMappings, $item->expression->field);
foreach ($possibleAliases as $alias) {
if ($this->rsm->columnOwnerMap[$alias] == $item->expression->identificationVariable) {
$sqlOrderColumns[] = $alias;
$orderBy[] = $alias . ' ' . $item->type;
break;
}
}
}
//remove identifier aliases
$sqlOrderColumns = array_diff($sqlOrderColumns, $sqlIdentifier);
}
//we don't need orderBy in inner query
//However at least on 5.4.6 I'm getting a segmentation fault and thus we don't clear it for now
/*$AST->orderByClause = null;
$sql = parent::walkSelectStatement($AST);*/
if (count($orderBy)) {
$sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result ORDER BY %s',
implode(', ', array_merge($sqlIdentifier, $sqlOrderColumns)), $sql, implode(', ', $orderBy));
} else {
$sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result', $sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result',
implode(', ', $sqlIdentifier), $sql); implode(', ', $sqlIdentifier), $sql);
}
} else {
$sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result',
implode(', ', $sqlIdentifier), $sql);
}
// Apply the limit and offset // Apply the limit and offset
$sql = $this->platform->modifyLimitQuery( $sql = $this->platform->modifyLimitQuery(

View File

@ -10,14 +10,42 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
{ {
$query = $this->entityManager->createQuery( $query = $this->entityManager->createQuery(
'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a'); 'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a');
$query->expireQueryCache(true);
$limitQuery = clone $query; $limitQuery = clone $query;
$limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker'); $limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker');
$this->assertEquals( $this->assertEquals(
"SELECT DISTINCT id0 FROM (SELECT m0_.id AS id0, c1_.id AS id1, a2_.id AS id2, a2_.name AS name3, m0_.author_id AS author_id4, m0_.category_id AS category_id5 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result", $limitQuery->getSql() "SELECT DISTINCT id0 FROM (SELECT m0_.id AS id0, m0_.title AS title1, c1_.id AS id2, a2_.id AS id3, a2_.name AS name4, m0_.author_id AS author_id5, m0_.category_id AS category_id6 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id) dctrn_result", $limitQuery->getSql()
); );
} }
public function testLimitSubqueryWithSortPg()
{
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
$this->entityManager->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\PostgreSqlPlatform);
$query = $this->entityManager->createQuery(
'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a ORDER BY p.title');
$limitQuery = clone $query;
$limitQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker');
$this->assertEquals(
"SELECT DISTINCT id0, title1 FROM (SELECT m0_.id AS id0, m0_.title AS title1, c1_.id AS id2, a2_.id AS id3, a2_.name AS name4, m0_.author_id AS author_id5, m0_.category_id AS category_id6 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id ORDER BY m0_.title ASC) dctrn_result ORDER BY title1 ASC", $limitQuery->getSql()
);
$this->entityManager->getConnection()->setDatabasePlatform($odp);
}
public function testLimitSubqueryPg()
{
$odp = $this->entityManager->getConnection()->getDatabasePlatform();
$this->entityManager->getConnection()->setDatabasePlatform(new \Doctrine\DBAL\Platforms\PostgreSqlPlatform);
$this->testLimitSubquery();
$this->entityManager->getConnection()->setDatabasePlatform($odp);
}
public function testCountQuery_MixedResultsWithName() public function testCountQuery_MixedResultsWithName()
{ {
$query = $this->entityManager->createQuery( $query = $this->entityManager->createQuery(

View File

@ -21,6 +21,18 @@ class LimitSubqueryWalkerTest extends PaginationTestCase
); );
} }
public function testLimitSubqueryWithSort()
{
$query = $this->entityManager->createQuery(
'SELECT p, c, a FROM Doctrine\Tests\ORM\Tools\Pagination\MyBlogPost p JOIN p.category c JOIN p.author a ORDER BY p.title');
$limitQuery = clone $query;
$limitQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('Doctrine\ORM\Tools\Pagination\LimitSubqueryWalker'));
$this->assertEquals(
"SELECT DISTINCT m0_.id AS id0, m0_.title AS title1 FROM MyBlogPost m0_ INNER JOIN Category c1_ ON m0_.category_id = c1_.id INNER JOIN Author a2_ ON m0_.author_id = a2_.id ORDER BY m0_.title ASC", $limitQuery->getSql()
);
}
public function testCountQuery_MixedResultsWithName() public function testCountQuery_MixedResultsWithName()
{ {
$query = $this->entityManager->createQuery( $query = $this->entityManager->createQuery(

View File

@ -31,6 +31,8 @@ class MyBlogPost
* @ManyToOne(targetEntity="Category") * @ManyToOne(targetEntity="Category")
*/ */
public $category; public $category;
/** @column(type="string") */
public $title;
} }
/** /**