Browse Source

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 years ago
parent
commit
8a5d65cebe
2 changed files with 49 additions and 0 deletions
  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->_sqlCompiler($sql, $query, $generator),
             $this->{'_' . $type . 'Parts'}
             $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;
         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
      * Test that deep containments don't generate empty entities for
      * intermediary relations.
      * intermediary relations.
      *
      *