Browse Source

Fix missing parentheses when ordering by query expression.

ndm2 5 years ago
parent
commit
059e9b20ba

+ 4 - 1
src/Database/Expression/OrderClauseExpression.php

@@ -15,6 +15,7 @@
 namespace Cake\Database\Expression;
 
 use Cake\Database\ExpressionInterface;
+use Cake\Database\Query;
 use Cake\Database\ValueBinder;
 
 /**
@@ -49,7 +50,9 @@ class OrderClauseExpression implements ExpressionInterface, FieldInterface
     public function sql(ValueBinder $generator)
     {
         $field = $this->_field;
-        if ($field instanceof ExpressionInterface) {
+        if ($field instanceof Query) {
+            $field = sprintf('(%s)', $field->sql($generator));
+        } elseif ($field instanceof ExpressionInterface) {
             $field = $field->sql($generator);
         }
 

+ 67 - 0
tests/TestCase/Database/QueryTest.php

@@ -5090,4 +5090,71 @@ class QueryTest extends TestCase
         $results = $statement->fetchColumn(3);
         $this->assertFalse($results);
     }
+
+    /**
+     * Tests that query expressions can be used for ordering.
+     *
+     * @return void
+     */
+    public function testOrderBySubquery()
+    {
+        $this->autoQuote = true;
+        $this->connection->getDriver()->enableAutoQuoting($this->autoQuote);
+
+        $this->loadFixtures('Articles');
+        $connection = $this->connection;
+
+        $query = new Query($connection);
+
+        $stmt = $connection->update('articles', ['published' => 'N'], ['id' => 3]);
+        $stmt->closeCursor();
+
+        $subquery = new Query($connection);
+        $subquery
+            ->select(
+                $subquery->newExpr()->addCase(
+                    [$subquery->newExpr()->add(['a.published' => 'N'])],
+                    [1, 0],
+                    ['integer', 'integer']
+                )
+            )
+            ->from(['a' => 'articles'])
+            ->where([
+                'a.id = articles.id',
+            ]);
+
+        $query
+            ->select(['id'])
+            ->from('articles')
+            ->orderDesc($subquery)
+            ->orderAsc('id')
+            ->setSelectTypeMap(new TypeMap([
+                'id' => 'integer',
+            ]));
+
+        $this->assertQuotedQuery(
+            'SELECT <id> FROM <articles> ORDER BY \(' .
+                'SELECT \(CASE WHEN <a>\.<published> = \:c0 THEN \:param1 ELSE \:param2 END\) ' .
+                'FROM <articles> <a> ' .
+                'WHERE a\.id = articles\.id' .
+            '\) DESC, <id> ASC',
+            $query->sql(),
+            !$this->autoQuote
+        );
+
+        $this->assertSame(
+            [
+                [
+                    'id' => 3,
+                ],
+                [
+                    'id' => 1,
+                ],
+                [
+                    'id' => 2,
+                ],
+            ],
+            $query->execute()->fetchAll('assoc')
+        );
+    }
 }