From dfa9f3cc52b348d5c88278a338f2decbcefec388 Mon Sep 17 00:00:00 2001 From: Niek van Asperen Date: Fri, 12 Sep 2025 12:32:40 +0200 Subject: [PATCH 1/2] Fix bindings in url query string --- src/Query/Query.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Query/Query.php b/src/Query/Query.php index 0c4b979..1773da8 100644 --- a/src/Query/Query.php +++ b/src/Query/Query.php @@ -12,6 +12,11 @@ class Query */ protected $sql; + /** + * @var string + */ + protected $originalSql; + /** * @var string|null */ @@ -52,7 +57,7 @@ public function __construct($sql, $degenerations = []) { throw new QueryException('Empty Query'); } - $this->sql = $sql; + $this->sql = $this->originalSql = $sql; $this->degenerations = $degenerations; } @@ -110,7 +115,7 @@ public function getFormat() public function isUseInUrlBindingsParams():bool { // 'query=select {p1:UInt8} + {p2:UInt8}' -F "param_p1=3" -F "param_p2=4" - return preg_match('#{[\w+]+:[\w+()]+}#',$this->sql); + return preg_match('#{[\w+]+:[\w+()]+}#',$this->originalSql); } public function getUrlBindingsParams():array From a6825a9c40dadb4d28e41bf762bbcafcf71649fa Mon Sep 17 00:00:00 2001 From: Niek van Asperen Date: Fri, 12 Sep 2025 14:25:40 +0200 Subject: [PATCH 2/2] Fix backwards compatibility --- src/Query/Query.php | 17 +++++++++++++- tests/QueryTest.php | 55 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 tests/QueryTest.php diff --git a/src/Query/Query.php b/src/Query/Query.php index 1773da8..51bd638 100644 --- a/src/Query/Query.php +++ b/src/Query/Query.php @@ -3,6 +3,8 @@ namespace ClickHouseDB\Query; use ClickHouseDB\Exception\QueryException; +use ClickHouseDB\Query\Degeneration\Bindings; +use ClickHouseDB\Query\Degeneration\Conditions; use function sizeof; class Query @@ -112,10 +114,16 @@ public function getFormat() return $this->format; } + /** + * Check if the sql contains bindings like {p1:UInt8}. + * + * Check the original SQL before degeneration to prevent data that matches the same regex by accident causing adding bindings to the url + * For backwards compatibility use the degenerated sql when custom degenerations are found + */ public function isUseInUrlBindingsParams():bool { // 'query=select {p1:UInt8} + {p2:UInt8}' -F "param_p1=3" -F "param_p2=4" - return preg_match('#{[\w+]+:[\w+()]+}#',$this->originalSql); + return preg_match('#{[\w+]+:[\w+()]+}#', $this->hasCustomDegenerations() ? $this->sql : $this->originalSql); } public function getUrlBindingsParams():array @@ -165,4 +173,11 @@ public function __toString() { return $this->toSql(); } + + private function hasCustomDegenerations(): bool + { + return count(array_filter($this->degenerations, function (Degeneration $degeneration) { + return !in_array($degeneration::class, [Conditions::class, Bindings::class]); + })) > 0; + } } diff --git a/tests/QueryTest.php b/tests/QueryTest.php new file mode 100644 index 0000000..34e20a0 --- /dev/null +++ b/tests/QueryTest.php @@ -0,0 +1,55 @@ +assertEquals('SELECT {p1:UInt8} + {p2:UInt8}', $query->toSql()); + $this->assertTrue($query->isUseInUrlBindingsParams()); + } + + /** + * Test that isUseInUrlBindingsParams returns false when SQL doesn't contain a binding with the format {param:type} + */ + public function testIsUseInUrlBindingsParamsWithNoBinding(): void + { + $sql = 'SELECT 1 + :two'; + $degeneration = new Degeneration\Bindings(); + $degeneration->bindParams([ + 'two' => 2, + ]); + $query = new Query($sql, [$degeneration]); + + $this->assertEquals('SELECT 1 + 2', $query->toSql()); + $this->assertFalse($query->isUseInUrlBindingsParams()); + } + + /** + * Test that isUseInUrlBindingsParams returns false when SQL contains a similar pattern in a binding value + */ + public function testIsUseInUrlBindingsParamsWithSimilarPatternInValue(): void + { + $sql = 'INSERT INTO a (b) VALUES (:simple_bind)'; + $degeneration = new Degeneration\Bindings(); + $degeneration->bindParams([ + 'simple_bind' => '{foo:bar}', + ]); + $query = new Query($sql, [$degeneration]); + + $this->assertEquals("INSERT INTO a (b) VALUES ('{foo:bar}')", $query->toSql()); + $this->assertFalse($query->isUseInUrlBindingsParams()); + } +} \ No newline at end of file