Browse Source

Change previous SQL Server order fix to create a new order clause.

Avoid using pass by reference.
Mike Fellows 8 years ago
parent
commit
74bb8737f7
1 changed files with 20 additions and 20 deletions
  1. 20 20
      src/Database/Dialect/SqlserverDialectTrait.php

+ 20 - 20
src/Database/Dialect/SqlserverDialectTrait.php

@@ -106,30 +106,30 @@ trait SqlserverDialectTrait
         $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)