Skip to content

Commit 8a6a8dd

Browse files
committed
Fix handling null in SELECT, WHERE and HAVING
1 parent 4d4693c commit 8a6a8dd

File tree

8 files changed

+52
-24
lines changed

8 files changed

+52
-24
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 17 deletions
This file was deleted.

phpstan.neon.dist

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,3 @@ parameters:
77
ignoreErrors:
88
# Adds unnecessary maintanence overhead. We rather rely on PHPStan telling us the method returns unhandled FALSE
99
- "~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~"
10-
11-
includes:
12-
- phpstan-baseline.neon

psalm-baseline.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<files psalm-version="4.3.1@2feba22a005a18bf31d4c7b9bdb9252c73897476">
3+
<file src="src/Sql/SqlFactory.php">
4+
<InvalidReturnStatement occurrences="1">
5+
<code>$query</code>
6+
</InvalidReturnStatement>
7+
<InvalidReturnType occurrences="1">
8+
<code>string</code>
9+
</InvalidReturnType>
10+
<PossiblyInvalidArgument occurrences="1">
11+
<code>$query</code>
12+
</PossiblyInvalidArgument>
13+
</file>
14+
</files>

psalm.xml.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
55
xmlns="https://getpsalm.org/schema/config"
66
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
7+
errorBaseline="psalm-baseline.xml"
78
>
89
<projectFiles>
910
<directory name="src"/>

src/Sql/SqlFactory.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
namespace SimPod\ClickHouseClient\Sql;
66

7-
use function preg_replace;
7+
use function Safe\preg_replace;
88
use function Safe\sprintf;
99
use function str_replace;
1010

@@ -30,6 +30,8 @@ public function createWithParameters(string $query, array $parameters) : string
3030
);
3131
}
3232

33+
$query = preg_replace('~ ?=([\s]*?)IS NULL~', '$1IS NULL', $query);
34+
3335
return $query;
3436
}
3537
}

src/Sql/ValueFormatter.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,14 @@ public function format($value, ?string $paramName = null, ?string $sql = null) :
5050
}
5151

5252
if ($value === null) {
53-
return 'IS NULL';
53+
if (
54+
$paramName !== null && $sql !== null
55+
&& preg_match(sprintf('~(HAVING|WHERE)[\s\S]*?=\s*?:%s~', $paramName), $sql) === 1
56+
) {
57+
return 'IS NULL';
58+
}
59+
60+
return 'NULL';
5461
}
5562

5663
if ($value instanceof DateTimeImmutable) {
@@ -72,7 +79,7 @@ public function format($value, ?string $paramName = null, ?string $sql = null) :
7279
if (is_array($value)) {
7380
if (
7481
$paramName !== null && $sql !== null
75-
&& preg_match(sprintf('~\s+IN\s+\\(:%s\\)~', $paramName), $sql) === 1
82+
&& preg_match(sprintf('~\s+?IN\s+?\\(:%s\\)~', $paramName), $sql) === 1
7683
) {
7784
return implode(
7885
',',

tests/Sql/SqlFactoryTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,16 @@ public function providerCreateWithParameters() : iterable
6060
],
6161
];
6262

63+
yield 'null filter' => [
64+
<<<CLICKHOUSE
65+
SELECT 1 FROM system.one WHERE dummy IS NULL
66+
CLICKHOUSE,
67+
<<<CLICKHOUSE
68+
SELECT 1 FROM system.one WHERE dummy = :null
69+
CLICKHOUSE,
70+
['null' => null],
71+
];
72+
6373
yield 'escape backslash' => [
6474
<<<CLICKHOUSE
6575
SELECT toIPv6('x\\\\')

tests/Sql/ValueFormatterTest.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,21 @@ public function providerFormat() : iterable
3737
yield 'float .5' => ['1.5', 1.5];
3838
yield 'string' => ["'ping'", 'ping'];
3939
yield 'string escaped' => ["'ping\\\\n'", 'ping\n'];
40-
yield 'null' => ['IS NULL', null];
40+
yield 'null' => ['NULL', null];
41+
yield 'null with WHERE' => ['IS NULL', null, 'null', 'SELECT 1 FROM table WHERE x = :null'];
42+
yield 'null with multiline WHERE' => [
43+
'IS NULL',
44+
null,
45+
'null',
46+
<<<SQL
47+
SELECT 1 FROM table WHERE
48+
1 = 1
49+
AND x = :null
50+
SQL,
51+
];
52+
53+
yield 'null with HAVING' => ['IS NULL', null, 'null', 'SELECT 1 FROM table HAVING x = :null'];
54+
yield 'null with SELECT' => ['NULL', null, 'SELECT :null'];
4155
yield 'array' => ["['a','b','c']", ['a', 'b', 'c']];
4256
yield 'array in array' => ["[['a']]", [['a']]];
4357
yield 'array with null' => ['[NULL]', [null]];

0 commit comments

Comments
 (0)