1
0
mirror of synced 2024-12-13 14:56:01 +03:00

Merge pull request #449 from mvrhov/DDC-1958

Pager fix for DDC-1958
This commit is contained in:
Benjamin Eberlei 2012-11-12 06:02:32 -08:00
commit 918ea1cdd8
4 changed files with 94 additions and 3 deletions

View File

@ -15,6 +15,7 @@ namespace Doctrine\ORM\Tools\Pagination;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\AST\SelectStatement;
use Doctrine\DBAL\Platforms\PostgreSqlPlatform;
/**
* Wrap the query in order to select root entity IDs for pagination
@ -85,7 +86,7 @@ class LimitSubqueryOutputWalker extends SqlWalker
*/
public function walkSelectStatement(SelectStatement $AST)
{
$sql = parent::walkSelectStatement($AST);
$innerSql = parent::walkSelectStatement($AST);
// Find out the SQL alias of the identifier column of the root entity
// It may be possible to make this work with multiple root entities but that
@ -133,7 +134,12 @@ class LimitSubqueryOutputWalker extends SqlWalker
// Build the counter query
$sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result',
implode(', ', $sqlIdentifier), $sql);
implode(', ', $sqlIdentifier), $innerSql);
if ($this->platform instanceof PostgreSqlPlatform) {
//http://www.doctrine-project.org/jira/browse/DDC-1958
$this->getPostgresqlSql($AST, $sqlIdentifier, $innerSql, $sql);
}
// Apply the limit and offset
$sql = $this->platform->modifyLimitQuery(
@ -150,4 +156,47 @@ class LimitSubqueryOutputWalker extends SqlWalker
return $sql;
}
/**
* Generate new SQL for postgresql if necessary
*
* @param SelectStatement $AST
* @param array sqlIdentifier
* @param string $sql
*/
public function getPostgresqlSql(SelectStatement $AST, array $sqlIdentifier, $innerSql, &$sql)
{
// 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;
$innerSql = parent::walkSelectStatement($AST);*/
if (count($orderBy)) {
$sql = sprintf(
'SELECT DISTINCT %s FROM (%s) dctrn_result ORDER BY %s',
implode(', ', array_merge($sqlIdentifier, $sqlOrderColumns)),
$innerSql,
implode(', ', $orderBy)
);
}
}
}

View File

@ -10,14 +10,42 @@ class LimitSubqueryOutputWalkerTest extends PaginationTestCase
{
$query = $this->entityManager->createQuery(
'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->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\LimitSubqueryOutputWalker');
$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()
{
$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()
{
$query = $this->entityManager->createQuery(

View File

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