From 74bb8737f784976610773d7f5e5b8ab977e51ada Mon Sep 17 00:00:00 2001 From: Mike Fellows Date: Wed, 26 Jul 2017 09:26:16 -0700 Subject: [PATCH] Change previous SQL Server order fix to create a new order clause. Avoid using pass by reference. --- .../Dialect/SqlserverDialectTrait.php | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Database/Dialect/SqlserverDialectTrait.php b/src/Database/Dialect/SqlserverDialectTrait.php index f894836b368..a58161c0861 100644 --- a/src/Database/Dialect/SqlserverDialectTrait.php +++ b/src/Database/Dialect/SqlserverDialectTrait.php @@ -106,30 +106,30 @@ protected function _pagingSubquery($original, $limit, $offset) $field = '_cake_paging_._cake_page_rownum_'; if ($original->clause('order')) { - $order = clone $original->clause('order'); + // SQL server does not support column aliases in OVER clauses. But + // the only practical way to specify the use of calculated columns + // is with their alias. So substitute the select SQL in place of + // any column aliases for those entries in the order clause. + $select = $original->clause('select'); + $order = new OrderByExpression(); + $original + ->clause('order') + ->iterateParts(function ($direction, $orderBy) use ($select, $order) { + $key = $orderBy; + if (isset($select[$orderBy]) && + $select[$orderBy] instanceof ExpressionInterface + ) { + $key = $select[$orderBy]->sql(new ValueBinder()); + } + $order->add([$key => $direction]); + + // Leave original order clause unchanged. + return $orderBy; + }); } else { $order = new OrderByExpression('(SELECT NULL)'); } - // SQL server does not support column aliases in OVER clauses. But for - // calculated columns the alias is the only practical identifier to use - // when specifying the order. So if a column alias is specified in the - // order clause, and the value of that alias is an expression, change - // the alias into what it represents by setting the clause's key to be - // the SQL representation of its value. The UnaryExpression creation - // below will then do the right thing and use the calculation in the - // ROW_NUMBER() OVER clause instead of the alias. - $select = $original->clause('select'); - $order->iterateParts(function ($direction, &$orderBy) use ($select) { - if (isset($select[$orderBy])) { - if ($select[$orderBy] instanceof ExpressionInterface) { - $orderBy = $select[$orderBy]->sql(new ValueBinder()); - } - } - - return $direction; - }); - $query = clone $original; $query->select([ '_cake_page_rownum_' => new UnaryExpression('ROW_NUMBER() OVER', $order)