浏览代码

Fix bound parameters in sub-queries not working.

By applying the bound parameters when the valueBinder is different than
the current query's binder we can propagate bound variables from
subqueries to the parent query. The caveat being that this only works
seamlessly for named parameters. Numbered parameters still have a chance
of overlapping.

Refs #8466
Mark Story 10 年之前
父节点
当前提交
8a5d65cebe
共有 2 个文件被更改,包括 49 次插入0 次删除
  1. 7 0
      src/Database/QueryCompiler.php
  2. 42 0
      tests/TestCase/ORM/QueryRegressionTest.php

+ 7 - 0
src/Database/QueryCompiler.php

@@ -97,6 +97,13 @@ class QueryCompiler
             $this->_sqlCompiler($sql, $query, $generator),
             $this->{'_' . $type . 'Parts'}
         );
+
+        // Propagate bound parameters from sub-queries
+        if ($query->valueBinder() !== $generator) {
+            foreach ($query->valueBinder()->bindings() as $binding) {
+                $generator->bind(':' . $binding['placeholder'], $binding['value'], $binding['type']);
+            }
+        }
         return $sql;
     }
 

+ 42 - 0
tests/TestCase/ORM/QueryRegressionTest.php

@@ -581,6 +581,48 @@ class QueryRegressionTest extends TestCase
     }
 
     /**
+     * Tests that getting the count of a query with bind is correct
+     *
+     * @see https://github.com/cakephp/cakephp/issues/8466
+     * @return void
+     */
+    public function testCountWithBind()
+    {
+        $table = TableRegistry::get('Articles');
+        $query = $table
+            ->find()
+            ->select(['Articles.title', 'Articles.id'])
+            ->where("Articles.title LIKE :val")
+            ->group('Articles.id')
+            ->bind(':val', '%Second%');
+        $count = $query->count();
+        $this->assertEquals(1, $count);
+    }
+
+    /**
+     * Tests that bind in subqueries works.
+     *
+     * @return void
+     */
+    public function testSubqueryBind()
+    {
+        $table = TableRegistry::get('Articles');
+        $sub = $table->find()
+            ->select(['Articles.id'])
+            ->where("Articles.title LIKE :val")
+            ->bind(':val', 'Second %');
+
+        $query = $table
+            ->find()
+            ->select(['Articles.title'])
+            ->where(["Articles.id NOT IN" => $sub]);
+        $result = $query->toArray();
+        $this->assertCount(2, $result);
+        $this->assertEquals('First Article', $result[0]->title);
+        $this->assertEquals('Third Article', $result[1]->title);
+    }
+
+    /**
      * Test that deep containments don't generate empty entities for
      * intermediary relations.
      *