diff --git a/src/Query/Query.php b/src/Query/Query.php index 0c4b979..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 @@ -12,6 +14,11 @@ class Query */ protected $sql; + /** + * @var string + */ + protected $originalSql; + /** * @var string|null */ @@ -52,7 +59,7 @@ public function __construct($sql, $degenerations = []) { throw new QueryException('Empty Query'); } - $this->sql = $sql; + $this->sql = $this->originalSql = $sql; $this->degenerations = $degenerations; } @@ -107,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->sql); + return preg_match('#{[\w+]+:[\w+()]+}#', $this->hasCustomDegenerations() ? $this->sql : $this->originalSql); } public function getUrlBindingsParams():array @@ -160,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