Fixed how order by items are included in the select list of the select distinct wrapper statement
This commit is contained in:
parent
7031539314
commit
dfc0910756
@ -13,6 +13,9 @@
|
|||||||
|
|
||||||
namespace Doctrine\ORM\Tools\Pagination;
|
namespace Doctrine\ORM\Tools\Pagination;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Platforms\MySqlPlatform;
|
||||||
|
use Doctrine\DBAL\Platforms\OraclePlatform;
|
||||||
|
use Doctrine\DBAL\Platforms\SQLServerPlatform;
|
||||||
use Doctrine\ORM\Query\AST\OrderByClause;
|
use Doctrine\ORM\Query\AST\OrderByClause;
|
||||||
use Doctrine\ORM\Query\AST\PathExpression;
|
use Doctrine\ORM\Query\AST\PathExpression;
|
||||||
use Doctrine\ORM\Query\SqlWalker;
|
use Doctrine\ORM\Query\SqlWalker;
|
||||||
@ -214,27 +217,23 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
|||||||
*/
|
*/
|
||||||
public function preserveSqlOrdering(array $sqlIdentifier, $innerSql, $sql, $orderByClause)
|
public function preserveSqlOrdering(array $sqlIdentifier, $innerSql, $sql, $orderByClause)
|
||||||
{
|
{
|
||||||
// Get order by clause as a string
|
|
||||||
$orderBy = null;
|
|
||||||
if ($orderByClause instanceof OrderByClause) {
|
|
||||||
$orderBy = $this->walkOrderByClause($orderByClause);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the sql statement has an order by clause, we need to wrap it in a new select distinct
|
// If the sql statement has an order by clause, we need to wrap it in a new select distinct
|
||||||
// statement
|
// statement
|
||||||
if ($orderBy) {
|
if ($orderByClause instanceof OrderByClause) {
|
||||||
// Rebuild the order by clause to work in the scope of the new select statement
|
// Rebuild the order by clause to work in the scope of the new select statement
|
||||||
list($sqlOrderColumns, $orderBy) = $this->rebuildOrderByClauseForOuterScope($orderBy);
|
/** @var array $sqlOrderColumns an array of items that need to be included in the select list */
|
||||||
|
/** @var array $orderBy an array of rebuilt order by items */
|
||||||
|
list($sqlOrderColumns, $orderBy) = $this->rebuildOrderByClauseForOuterScope($orderByClause);
|
||||||
|
|
||||||
// Identifiers are always included in the select list, so there's no need to include them twice
|
// Identifiers are always included in the select list, so there's no need to include them twice
|
||||||
$sqlOrderColumns = array_diff($sqlOrderColumns, $sqlIdentifier);
|
$sqlOrderColumns = array_diff($sqlOrderColumns, $sqlIdentifier);
|
||||||
|
|
||||||
// Build the select distinct statement
|
// Build the select distinct statement
|
||||||
$sql = sprintf(
|
$sql = sprintf(
|
||||||
'SELECT DISTINCT %s FROM (%s) dctrn_result%s',
|
'SELECT DISTINCT %s FROM (%s) dctrn_result ORDER BY %s',
|
||||||
implode(', ', array_merge($sqlIdentifier, $sqlOrderColumns)),
|
implode(', ', array_merge($sqlIdentifier, $sqlOrderColumns)),
|
||||||
$innerSql,
|
$innerSql,
|
||||||
$orderBy
|
implode(', ', $orderBy)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,15 +243,16 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
|||||||
/**
|
/**
|
||||||
* Generates a new order by clause that works in the scope of a select query wrapping the original
|
* Generates a new order by clause that works in the scope of a select query wrapping the original
|
||||||
*
|
*
|
||||||
* @param string $orderByClause
|
* @param OrderByClause $orderByClause
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function rebuildOrderByClauseForOuterScope($orderByClause) {
|
protected function rebuildOrderByClauseForOuterScope(OrderByClause $orderByClause) {
|
||||||
$dqlAliasToSqlTableAliasMap
|
$dqlAliasToSqlTableAliasMap
|
||||||
= $searchPatterns
|
= $searchPatterns
|
||||||
= $replacements
|
= $replacements
|
||||||
= $dqlAliasToClassMap
|
= $dqlAliasToClassMap
|
||||||
= $replacedAliases
|
= $selectListAdditions
|
||||||
|
= $orderByItems
|
||||||
= array();
|
= array();
|
||||||
|
|
||||||
// Generate DQL alias -> SQL table alias mapping
|
// Generate DQL alias -> SQL table alias mapping
|
||||||
@ -279,24 +279,20 @@ class LimitSubqueryOutputWalker extends SqlWalker
|
|||||||
$replacements[] = $fieldAlias;
|
$replacements[] = $fieldAlias;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scalar expression aliases will not be modified in the order by clause, but will
|
foreach($orderByClause->orderByItems as $orderByItem) {
|
||||||
// be included in the select list of the wrapping query
|
// Walk order by item to get string representation of it
|
||||||
$scalarSearchPattern = "/(?<![a-z0-9_])%s(?![a-z0-9_])/i";
|
$orderByItem = $this->walkOrderByItem($orderByItem);
|
||||||
foreach(array_keys($this->rsm->scalarMappings) as $scalarField) {
|
|
||||||
if(preg_match(sprintf($scalarSearchPattern, $scalarField), $orderByClause)) {
|
// Replace path expressions in the order by clause with their column alias
|
||||||
$replacedAliases[] = $scalarField;
|
$orderByItem = preg_replace($searchPatterns, $replacements, $orderByItem);
|
||||||
}
|
|
||||||
|
// The order by items are not required to be in the select list on Oracle and PostgreSQL, but
|
||||||
|
// for the sake of simplicity, order by items will be included in the select list on all platforms.
|
||||||
|
// This doesn't impact functionality.
|
||||||
|
$selectListAdditions[] = trim(str_ireplace(array("asc", "desc"), "", $orderByItem));
|
||||||
|
$orderByItems[] = $orderByItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace path expressions in the order by clause with their column alias
|
return array($selectListAdditions, $orderByItems);
|
||||||
foreach($searchPatterns as $index => $pattern) {
|
|
||||||
$newOrderByClause = preg_replace($pattern, $replacements[$index], $orderByClause);
|
|
||||||
if ($newOrderByClause !== $orderByClause) {
|
|
||||||
$orderByClause = $newOrderByClause;
|
|
||||||
$replacedAliases[] = $replacements[$index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return array($replacedAliases, $orderByClause);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user