From 8a6a8dd2a05d691ecc312f00cb2e73926503c39a Mon Sep 17 00:00:00 2001 From: Simon Podlipsky Date: Tue, 22 Dec 2020 18:16:11 +0100 Subject: [PATCH] Fix handling null in SELECT, WHERE and HAVING --- phpstan-baseline.neon | 17 ----------------- phpstan.neon.dist | 3 --- psalm-baseline.xml | 14 ++++++++++++++ psalm.xml.dist | 1 + src/Sql/SqlFactory.php | 4 +++- src/Sql/ValueFormatter.php | 11 +++++++++-- tests/Sql/SqlFactoryTest.php | 10 ++++++++++ tests/Sql/ValueFormatterTest.php | 16 +++++++++++++++- 8 files changed, 52 insertions(+), 24 deletions(-) delete mode 100644 phpstan-baseline.neon create mode 100644 psalm-baseline.xml diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon deleted file mode 100644 index 6318dda..0000000 --- a/phpstan-baseline.neon +++ /dev/null @@ -1,17 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Function preg_replace is unsafe to use\\. It can return FALSE instead of throwing an exception\\. Please add 'use function Safe\\\\preg_replace;' at the beginning of the file to use the variant provided by the 'thecodingmachine/safe' library\\.$#" - count: 1 - path: src/Sql/SqlFactory.php - - - - message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#" - count: 1 - path: src/Sql/SqlFactory.php - - - - message: "#^Method SimPod\\\\ClickHouseClient\\\\Sql\\\\SqlFactory\\:\\:createWithParameters\\(\\) should return string but returns string\\|null\\.$#" - count: 1 - path: src/Sql/SqlFactory.php - diff --git a/phpstan.neon.dist b/phpstan.neon.dist index a9fb2b7..bcfd5d0 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -7,6 +7,3 @@ parameters: ignoreErrors: # Adds unnecessary maintanence overhead. We rather rely on PHPStan telling us the method returns unhandled FALSE - "~Class DateTime(Immutable)? is unsafe to use. Its methods can return FALSE instead of throwing an exception. Please add 'use Safe\\\\DateTime(Immutable)?;' at the beginning of the file to use the variant provided by the 'thecodingmachine/safe' library~" - -includes: - - phpstan-baseline.neon diff --git a/psalm-baseline.xml b/psalm-baseline.xml new file mode 100644 index 0000000..85ec2c3 --- /dev/null +++ b/psalm-baseline.xml @@ -0,0 +1,14 @@ + + + + + $query + + + string + + + $query + + + diff --git a/psalm.xml.dist b/psalm.xml.dist index 3191e3c..9dfbd98 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -4,6 +4,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" + errorBaseline="psalm-baseline.xml" > diff --git a/src/Sql/SqlFactory.php b/src/Sql/SqlFactory.php index 9fc050d..b978be6 100644 --- a/src/Sql/SqlFactory.php +++ b/src/Sql/SqlFactory.php @@ -4,7 +4,7 @@ namespace SimPod\ClickHouseClient\Sql; -use function preg_replace; +use function Safe\preg_replace; use function Safe\sprintf; use function str_replace; @@ -30,6 +30,8 @@ public function createWithParameters(string $query, array $parameters) : string ); } + $query = preg_replace('~ ?=([\s]*?)IS NULL~', '$1IS NULL', $query); + return $query; } } diff --git a/src/Sql/ValueFormatter.php b/src/Sql/ValueFormatter.php index 57d0082..7992e44 100644 --- a/src/Sql/ValueFormatter.php +++ b/src/Sql/ValueFormatter.php @@ -50,7 +50,14 @@ public function format($value, ?string $paramName = null, ?string $sql = null) : } if ($value === null) { - return 'IS NULL'; + if ( + $paramName !== null && $sql !== null + && preg_match(sprintf('~(HAVING|WHERE)[\s\S]*?=\s*?:%s~', $paramName), $sql) === 1 + ) { + return 'IS NULL'; + } + + return 'NULL'; } if ($value instanceof DateTimeImmutable) { @@ -72,7 +79,7 @@ public function format($value, ?string $paramName = null, ?string $sql = null) : if (is_array($value)) { if ( $paramName !== null && $sql !== null - && preg_match(sprintf('~\s+IN\s+\\(:%s\\)~', $paramName), $sql) === 1 + && preg_match(sprintf('~\s+?IN\s+?\\(:%s\\)~', $paramName), $sql) === 1 ) { return implode( ',', diff --git a/tests/Sql/SqlFactoryTest.php b/tests/Sql/SqlFactoryTest.php index d0e0bb6..05e81f8 100644 --- a/tests/Sql/SqlFactoryTest.php +++ b/tests/Sql/SqlFactoryTest.php @@ -60,6 +60,16 @@ public function providerCreateWithParameters() : iterable ], ]; + yield 'null filter' => [ + << null], + ]; + yield 'escape backslash' => [ << ['1.5', 1.5]; yield 'string' => ["'ping'", 'ping']; yield 'string escaped' => ["'ping\\\\n'", 'ping\n']; - yield 'null' => ['IS NULL', null]; + yield 'null' => ['NULL', null]; + yield 'null with WHERE' => ['IS NULL', null, 'null', 'SELECT 1 FROM table WHERE x = :null']; + yield 'null with multiline WHERE' => [ + 'IS NULL', + null, + 'null', + << ['IS NULL', null, 'null', 'SELECT 1 FROM table HAVING x = :null']; + yield 'null with SELECT' => ['NULL', null, 'SELECT :null']; yield 'array' => ["['a','b','c']", ['a', 'b', 'c']]; yield 'array in array' => ["[['a']]", [['a']]]; yield 'array with null' => ['[NULL]', [null]];