Skip to content

Commit

Permalink
SqlPreprocessor: support for IN (?) [Closes #256]
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Oct 6, 2020
1 parent b0e102f commit a9e5763
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 2 deletions.
8 changes: 7 additions & 1 deletion src/Database/SqlPreprocessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public function process(array $params, bool $useParams = false): array
$this->arrayMode = null;
$res[] = Nette\Utils\Strings::replace(
$param,
'~\'[^\']*+\'|"[^"]*+"|\?[a-z]*|^\s*+(?:\(?\s*SELECT|INSERT|UPDATE|DELETE|REPLACE|EXPLAIN)\b|\b(?:SET|WHERE|HAVING|ORDER BY|GROUP BY|KEY UPDATE)(?=\s*$|\s*\?)|/\*.*?\*/|--[^\n]*~Dsi',
'~\'[^\']*+\'|"[^"]*+"|\?[a-z]*|^\s*+(?:\(?\s*SELECT|INSERT|UPDATE|DELETE|REPLACE|EXPLAIN)\b|\b(?:SET|WHERE|HAVING|ORDER BY|GROUP BY|KEY UPDATE)(?=\s*$|\s*\?)|\bIN\s+\(\?\)|/\*.*?\*/|--[^\n]*~Dsi',
\Closure::fromCallable([$this, 'callback'])
);
} else {
Expand All @@ -127,6 +127,12 @@ private function callback(array $m): string
} elseif ($m[0] === "'" || $m[0] === '"' || $m[0] === '/' || $m[0] === '-') { // string or comment
return $m;

} elseif (substr($m, -3) === '(?)') { // IN (?)
if ($this->counter >= count($this->params)) {
throw new Nette\InvalidArgumentException('There are more placeholders than passed parameters.');
}
return 'IN (' . $this->formatValue($this->params[$this->counter++], self::MODE_LIST) . ')';

} else { // command
$cmd = ltrim(strtoupper($m), "\t\n\r (");
$this->arrayMode = self::ARRAY_MODES[$cmd] ?? null;
Expand Down
7 changes: 6 additions & 1 deletion tests/Database/SqlPreprocessor.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ test('IN', function () use ($preprocessor) {

Assert::same(reformat('SELECT id FROM author WHERE ([a] IN (NULL, ?, ?, ?)) AND (1=0) AND ([c] NOT IN (NULL, ?, ?, ?))'), $sql);
Assert::same([1, 2, 3, 1, 2, 3], $params);


[$sql, $params] = $preprocessor->process(['SELECT * FROM table WHERE ? AND id IN (?) AND ?', ['a' => 111], [3, 4], ['b' => 222]]);
Assert::same(reformat('SELECT * FROM table WHERE ([a] = ?) AND id IN (?, ?) AND ([b] = ?)'), $sql);
Assert::same([111, 3, 4, 222], $params);
});


Expand Down Expand Up @@ -349,7 +354,7 @@ test('?values', function () use ($preprocessor) {

test('automatic detection failed', function () use ($preprocessor) {
Assert::exception(function () use ($preprocessor) {
$preprocessor->process(['INSERT INTO author (name) SELECT name FROM user WHERE id IN (?)', [11, 12]]);
dump($preprocessor->process(['INSERT INTO author (name) SELECT name FROM user WHERE id ?', [11, 12]])); // invalid sql
}, Nette\InvalidArgumentException::class, 'Automaticaly detected multi-insert, but values aren\'t array. If you need try to change mode like "?[and|or|set|values|order|list]". Mode "values" was used.');
});

Expand Down

0 comments on commit a9e5763

Please sign in to comment.