From 840858ab4dd9a051dfd0a5c7728b06fce1b85461 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Fri, 8 May 2020 01:10:49 +0200 Subject: [PATCH] SqlPreprocessor: support for IN (?) [Closes #256] --- src/Database/SqlPreprocessor.php | 8 +++++++- tests/Database/SqlPreprocessor.phpt | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Database/SqlPreprocessor.php b/src/Database/SqlPreprocessor.php index b59eb1670..1fbdbd422 100644 --- a/src/Database/SqlPreprocessor.php +++ b/src/Database/SqlPreprocessor.php @@ -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 { @@ -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; diff --git a/tests/Database/SqlPreprocessor.phpt b/tests/Database/SqlPreprocessor.phpt index db3385e4f..75392dae4 100644 --- a/tests/Database/SqlPreprocessor.phpt +++ b/tests/Database/SqlPreprocessor.phpt @@ -80,6 +80,11 @@ test(function () use ($preprocessor) { // IN 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); }); @@ -349,7 +354,7 @@ test(function () use ($preprocessor) { // ?values test(function () use ($preprocessor) { // automatic detection failed 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.'); });