diff --git a/.github/funding.yml b/.github/funding.yml
new file mode 100644
index 000000000..25adc9520
--- /dev/null
+++ b/.github/funding.yml
@@ -0,0 +1,2 @@
+github: dg
+custom: "https://nette.org/donate"
diff --git a/.travis.yml b/.travis.yml
index 3953da4f4..c963ec907 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,5 @@
language: php
php:
- - 7.1
- 7.2
- 7.3
- 7.4
diff --git a/appveyor.yml b/appveyor.yml
index 91ad14250..19c551fd4 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -22,7 +22,7 @@ install:
- IF EXIST c:\php (SET PHP=0) ELSE (SET PHP=1)
- IF %PHP%==1 mkdir c:\php
- IF %PHP%==1 cd c:\php
- - IF %PHP%==1 curl https://windows.php.net/downloads/releases/archives/php-7.1.5-Win32-VC14-x64.zip --output php.zip
+ - IF %PHP%==1 curl https://windows.php.net/downloads/releases/archives/php-7.2.28-Win32-VC15-x64.zip --output php.zip
- IF %PHP%==1 7z x php.zip >nul
- IF %PHP%==1 echo extension_dir=ext >> php.ini
- IF %PHP%==1 echo extension=php_openssl.dll >> php.ini
diff --git a/composer.json b/composer.json
index 46ebba32d..2278b57c8 100644
--- a/composer.json
+++ b/composer.json
@@ -15,7 +15,7 @@
}
],
"require": {
- "php": ">=7.1",
+ "php": ">=7.2",
"ext-pdo": "*",
"nette/caching": "^3.0",
"nette/utils": "^3.1"
@@ -40,7 +40,7 @@
},
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
}
}
diff --git a/readme.md b/readme.md
index ed8367cdc..9d0f9ca41 100644
--- a/readme.md
+++ b/readme.md
@@ -33,7 +33,7 @@ The recommended way to install is via Composer:
composer require nette/database
```
-It requires PHP version 7.1 and supports PHP up to 7.4.
+It requires PHP version 7.2 and supports PHP up to 7.4.
Usage
diff --git a/src/Bridges/DatabaseTracy/ConnectionPanel.php b/src/Bridges/DatabaseTracy/ConnectionPanel.php
index 0297b7c8a..f2004a946 100644
--- a/src/Bridges/DatabaseTracy/ConnectionPanel.php
+++ b/src/Bridges/DatabaseTracy/ConnectionPanel.php
@@ -34,6 +34,9 @@ class ConnectionPanel implements Tracy\IBarPanel
/** @var bool */
public $disabled = false;
+ /** @var float */
+ public $performanceScale = 0.25;
+
/** @var float logged time */
private $totalTime = 0;
@@ -46,11 +49,11 @@ class ConnectionPanel implements Tracy\IBarPanel
public function __construct(Connection $connection)
{
- $connection->onQuery[] = [$this, 'logQuery'];
+ $connection->onQuery[] = \Closure::fromCallable([$this, 'logQuery']);
}
- public function logQuery(Connection $connection, $result): void
+ private function logQuery(Connection $connection, $result): void
{
if ($this->disabled) {
return;
@@ -137,6 +140,7 @@ public function getPanel(): ?string
$name = $this->name;
$count = $this->count;
$totalTime = $this->totalTime;
+ $performanceScale = $this->performanceScale;
require __DIR__ . '/templates/ConnectionPanel.panel.phtml';
});
}
diff --git a/src/Bridges/DatabaseTracy/templates/ConnectionPanel.panel.phtml b/src/Bridges/DatabaseTracy/templates/ConnectionPanel.panel.phtml
index ef83eddf9..a31f7b9cb 100644
--- a/src/Bridges/DatabaseTracy/templates/ConnectionPanel.panel.phtml
+++ b/src/Bridges/DatabaseTracy/templates/ConnectionPanel.panel.phtml
@@ -29,7 +29,7 @@ use Tracy\Helpers;
[$connection, $sql, $params, $source, $time, $rows, $error, $command, $explain] = $query;
?>
-
+ |
ERROR
diff --git a/src/Database/Connection.php b/src/Database/Connection.php
index 18ffe26ac..7b589983e 100644
--- a/src/Database/Connection.php
+++ b/src/Database/Connection.php
@@ -152,6 +152,23 @@ public function rollBack(): void
}
+ /**
+ * @return mixed
+ */
+ public function transaction(callable $callback)
+ {
+ $this->beginTransaction();
+ try {
+ $res = $callback();
+ } catch (\Throwable $e) {
+ $this->rollBack();
+ throw $e;
+ }
+ $this->commit();
+ return $res;
+ }
+
+
/**
* Generates and executes SQL query.
*/
diff --git a/src/Database/Context.php b/src/Database/Context.php
index 280bd16f5..9cf68c1b4 100644
--- a/src/Database/Context.php
+++ b/src/Database/Context.php
@@ -60,6 +60,15 @@ public function rollBack(): void
}
+ /**
+ * @return mixed
+ */
+ public function transaction(callable $callback)
+ {
+ return $this->connection->transaction($callback);
+ }
+
+
public function getInsertId(string $sequence = null): string
{
return $this->connection->getInsertId($sequence);
diff --git a/src/Database/Drivers/MsSqlDriver.php b/src/Database/Drivers/MsSqlDriver.php
index b5793b9ab..d4e898b1f 100644
--- a/src/Database/Drivers/MsSqlDriver.php
+++ b/src/Database/Drivers/MsSqlDriver.php
@@ -45,6 +45,13 @@ public function delimite(string $name): string
}
+ public function undelimite(string $name): string
+ {
+ $name = preg_replace('#(?format("'Y-m-d H:i:s'");
diff --git a/src/Database/Drivers/MySqlDriver.php b/src/Database/Drivers/MySqlDriver.php
index 717efbe06..b7f7e321e 100644
--- a/src/Database/Drivers/MySqlDriver.php
+++ b/src/Database/Drivers/MySqlDriver.php
@@ -78,6 +78,13 @@ public function delimite(string $name): string
}
+ public function undelimite(string $name): string
+ {
+ $name = preg_replace('#(?format("'Y-m-d H:i:s'");
diff --git a/src/Database/Drivers/OciDriver.php b/src/Database/Drivers/OciDriver.php
index ac5a0e120..917303c7c 100644
--- a/src/Database/Drivers/OciDriver.php
+++ b/src/Database/Drivers/OciDriver.php
@@ -61,6 +61,13 @@ public function delimite(string $name): string
}
+ public function undelimite(string $name): string
+ {
+ $name = preg_replace('#(?format($this->fmtDateTime);
diff --git a/src/Database/Drivers/OdbcDriver.php b/src/Database/Drivers/OdbcDriver.php
index 3edda5e89..89755fa89 100644
--- a/src/Database/Drivers/OdbcDriver.php
+++ b/src/Database/Drivers/OdbcDriver.php
@@ -39,6 +39,13 @@ public function delimite(string $name): string
}
+ public function undelimite(string $name): string
+ {
+ $name = preg_replace('#(?format('#m/d/Y H:i:s#');
diff --git a/src/Database/Drivers/PgSqlDriver.php b/src/Database/Drivers/PgSqlDriver.php
index d58ec1481..9a295965c 100644
--- a/src/Database/Drivers/PgSqlDriver.php
+++ b/src/Database/Drivers/PgSqlDriver.php
@@ -63,6 +63,13 @@ public function delimite(string $name): string
}
+ public function undelimite(string $name): string
+ {
+ $name = preg_replace('#(?format("'Y-m-d H:i:s'");
diff --git a/src/Database/Drivers/SqliteDriver.php b/src/Database/Drivers/SqliteDriver.php
index 3a885bb19..1b852e209 100644
--- a/src/Database/Drivers/SqliteDriver.php
+++ b/src/Database/Drivers/SqliteDriver.php
@@ -74,6 +74,14 @@ public function delimite(string $name): string
}
+ public function undelimite(string $name): string
+ {
+ $name = preg_replace('#(?:^|\.)\[#', '', $name);
+ // Can not be fully undelimited due to ambigious delimite() - was delimited "[x x]" name originally "x x" or "x[]x"?
+ return $name;
+ }
+
+
public function formatDateTime(\DateTimeInterface $value): string
{
return $value->format($this->fmtDateTime);
diff --git a/src/Database/Drivers/SqlsrvDriver.php b/src/Database/Drivers/SqlsrvDriver.php
index a4f8661b9..beec8c3e8 100644
--- a/src/Database/Drivers/SqlsrvDriver.php
+++ b/src/Database/Drivers/SqlsrvDriver.php
@@ -49,6 +49,13 @@ public function delimite(string $name): string
}
+ public function undelimite(string $name): string
+ {
+ $name = preg_replace('#(?:^|\.)\[#', '', $name);
+ return str_replace(']]', ']', $name);
+ }
+
+
public function formatDateTime(\DateTimeInterface $value): string
{
/** @see https://msdn.microsoft.com/en-us/library/ms187819.aspx */
diff --git a/src/Database/Helpers.php b/src/Database/Helpers.php
index 9623a049b..a63e5ae45 100644
--- a/src/Database/Helpers.php
+++ b/src/Database/Helpers.php
@@ -33,6 +33,7 @@ class Helpers
'DATE' => IStructure::FIELD_DATE,
'(SMALL)?DATETIME(OFFSET)?\d*|TIME(STAMP.*)?' => IStructure::FIELD_DATETIME,
'BYTEA|(TINY|MEDIUM|LONG|)BLOB|(LONG )?(VAR)?BINARY|IMAGE' => IStructure::FIELD_BINARY,
+ 'REGCLASS' => IStructure::FIELD_TABLENAME,
];
diff --git a/src/Database/IStructure.php b/src/Database/IStructure.php
index 7c9e8bd39..0b93c8755 100644
--- a/src/Database/IStructure.php
+++ b/src/Database/IStructure.php
@@ -25,7 +25,8 @@ interface IStructure
FIELD_TIME = 'time',
FIELD_DATETIME = 'datetime',
FIELD_UNIX_TIMESTAMP = 'timestamp',
- FIELD_TIME_INTERVAL = 'timeint';
+ FIELD_TIME_INTERVAL = 'timeint',
+ FIELD_TABLENAME = 'regclass';
/**
* Returns tables list.
diff --git a/src/Database/ISupplementalDriver.php b/src/Database/ISupplementalDriver.php
index 69ca84966..424e242bb 100644
--- a/src/Database/ISupplementalDriver.php
+++ b/src/Database/ISupplementalDriver.php
@@ -38,6 +38,11 @@ function convertException(\PDOException $e): DriverException;
*/
function delimite(string $name): string;
+ /**
+ * Undelimites identifier as reverse operation for delimite (for example to get not delimited table name).
+ */
+ function undelimite(string $name): string;
+
/**
* Formats date-time for use in a SQL statement.
*/
diff --git a/src/Database/ResultSet.php b/src/Database/ResultSet.php
index 356638d76..6866f4bc6 100644
--- a/src/Database/ResultSet.php
+++ b/src/Database/ResultSet.php
@@ -161,6 +161,9 @@ public function normalizeRow(array $row): array
} elseif ($type === IStructure::FIELD_UNIX_TIMESTAMP) {
$row[$key] = Nette\Utils\DateTime::from($value);
+
+ } elseif ($type === IStructure::FIELD_TABLENAME) {
+ $row[$key] = $this->connection->getSupplementalDriver()->undelimite($value);
}
}
diff --git a/src/Database/SqlPreprocessor.php b/src/Database/SqlPreprocessor.php
index 0517f8dcc..1fbdbd422 100644
--- a/src/Database/SqlPreprocessor.php
+++ b/src/Database/SqlPreprocessor.php
@@ -19,18 +19,26 @@ class SqlPreprocessor
{
use Nette\SmartObject;
- /** @var array */
- private const MODE_LIST = ['and', 'or', 'set', 'values', 'order'];
+ private const
+ MODE_AND = 'and', // (key [operator] value) AND ...
+ MODE_OR = 'or', // (key [operator] value) OR ...
+ MODE_SET = 'set', // key=value, key=value, ...
+ MODE_VALUES = 'values', // (key, key, ...) VALUES (value, value, ...)
+ MODE_ORDER = 'order', // key, key DESC, ...
+ MODE_LIST = 'list', // value, value, ... | (tuple), (tuple), ...
+ MODE_AUTO = 'auto'; // arrayMode for arrays
+
+ private const MODES = [self::MODE_AND, self::MODE_OR, self::MODE_SET, self::MODE_VALUES, self::MODE_ORDER, self::MODE_LIST];
private const ARRAY_MODES = [
- 'INSERT' => 'values',
- 'REPLACE' => 'values',
- 'KEY UPDATE' => 'set',
- 'SET' => 'set',
- 'WHERE' => 'and',
- 'HAVING' => 'and',
- 'ORDER BY' => 'order',
- 'GROUP BY' => 'order',
+ 'INSERT' => self::MODE_VALUES,
+ 'REPLACE' => self::MODE_VALUES,
+ 'KEY UPDATE' => self::MODE_SET,
+ 'SET' => self::MODE_SET,
+ 'WHERE' => self::MODE_AND,
+ 'HAVING' => self::MODE_AND,
+ 'ORDER BY' => self::MODE_ORDER,
+ 'GROUP BY' => self::MODE_ORDER,
];
private const PARAMETRIC_COMMANDS = [
@@ -60,7 +68,7 @@ class SqlPreprocessor
/** @var bool */
private $useParams;
- /** @var string|null values|set|and|order */
+ /** @var string|null values|set|and|order|items */
private $arrayMode;
@@ -88,16 +96,15 @@ public function process(array $params, bool $useParams = false): array
$param = $params[$this->counter++];
if (($this->counter === 2 && count($params) === 2) || !is_scalar($param)) {
- $res[] = $this->formatValue($param, 'auto');
- $this->arrayMode = null;
+ $res[] = $this->formatValue($param, self::MODE_AUTO);
} elseif (is_string($param) && $this->counter > $prev + 1) {
$prev = $this->counter;
$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',
- [$this, 'callback']
+ '~\'[^\']*+\'|"[^"]*+"|\?[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 {
throw new Nette\InvalidArgumentException('There are more parameters than placeholders.');
@@ -108,19 +115,24 @@ public function process(array $params, bool $useParams = false): array
}
- /** @internal */
- public function callback(array $m): string
+ private function callback(array $m): string
{
$m = $m[0];
if ($m[0] === '?') { // placeholder
if ($this->counter >= count($this->params)) {
throw new Nette\InvalidArgumentException('There are more placeholders than passed parameters.');
}
- return $this->formatValue($this->params[$this->counter++], substr($m, 1) ?: 'auto');
+ return $this->formatValue($this->params[$this->counter++], substr($m, 1) ?: self::MODE_AUTO);
} 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;
@@ -132,7 +144,7 @@ public function callback(array $m): string
private function formatValue($value, string $mode = null): string
{
- if (!$mode || $mode === 'auto') {
+ if (!$mode || $mode === self::MODE_AUTO) {
if (is_scalar($value) || is_resource($value)) {
if ($this->useParams) {
$this->remaining[] = $value;
@@ -187,16 +199,16 @@ private function formatValue($value, string $mode = null): string
$value = iterator_to_array($value);
}
- if (is_array($value)) {
+ if ($mode && is_array($value)) {
$vx = $kx = [];
- if ($mode === 'auto') {
- $mode = $this->arrayMode;
+ if ($mode === self::MODE_AUTO) {
+ $mode = $this->arrayMode ?? self::MODE_LIST;
}
- if ($mode === 'values') { // (key, key, ...) VALUES (value, value, ...)
+ if ($mode === self::MODE_VALUES) { // (key, key, ...) VALUES (value, value, ...)
if (array_key_exists(0, $value)) { // multi-insert
if (!is_array($value[0]) && !$value[0] instanceof Row) {
- throw new Nette\InvalidArgumentException('Automaticaly detected multi-insert, but values aren\'t array. If you need try to change mode like "?[' . implode('|', self::MODE_LIST) . ']". Mode "' . $mode . '" was used.');
+ throw new Nette\InvalidArgumentException('Automaticaly detected multi-insert, but values aren\'t array. If you need try to change mode like "?[' . implode('|', self::MODES) . ']". Mode "' . $mode . '" was used.');
}
foreach ($value[0] as $k => $v) {
$kx[] = $this->delimite($k);
@@ -219,10 +231,10 @@ private function formatValue($value, string $mode = null): string
}
return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')';
- } elseif (!$mode || $mode === 'set') {
+ } elseif ($mode === self::MODE_SET) {
foreach ($value as $k => $v) {
- if (is_int($k)) { // value, value, ... OR (1, 2), (3, 4)
- $vx[] = is_array($v) ? '(' . $this->formatValue($v) . ')' : $this->formatValue($v);
+ if (is_int($k)) { // value, value, ...
+ $vx[] = $this->formatValue($v);
} elseif (substr($k, -1) === '=') { // key+=value, key-=value, ...
$k2 = $this->delimite(substr($k, 0, -2));
$vx[] = $k2 . '=' . $k2 . ' ' . substr($k, -2, 1) . ' ' . $this->formatValue($v);
@@ -232,7 +244,13 @@ private function formatValue($value, string $mode = null): string
}
return implode(', ', $vx);
- } elseif ($mode === 'and' || $mode === 'or') { // (key [operator] value) AND ...
+ } elseif ($mode === self::MODE_LIST) { // value, value, ... | (tuple), (tuple), ...
+ foreach ($value as $k => $v) {
+ $vx[] = is_array($v) ? '(' . $this->formatValue($v, self::MODE_LIST) . ')' : $this->formatValue($v);
+ }
+ return implode(', ', $vx);
+
+ } elseif ($mode === self::MODE_AND || $mode === self::MODE_OR) { // (key [operator] value) AND ...
foreach ($value as $k => $v) {
if (is_int($k)) {
$vx[] = $this->formatValue($v);
@@ -242,7 +260,7 @@ private function formatValue($value, string $mode = null): string
$k = $this->delimite($k);
if (is_array($v)) {
if ($v) {
- $vx[] = $k . ' ' . ($operator ? $operator . ' ' : '') . 'IN (' . $this->formatValue(array_values($v)) . ')';
+ $vx[] = $k . ' ' . ($operator ? $operator . ' ' : '') . 'IN (' . $this->formatValue(array_values($v), self::MODE_LIST) . ')';
} elseif ($operator === 'NOT') {
} else {
$vx[] = '1=0';
@@ -257,7 +275,7 @@ private function formatValue($value, string $mode = null): string
}
return $value ? '(' . implode(') ' . strtoupper($mode) . ' (', $vx) . ')' : '1=1';
- } elseif ($mode === 'order') { // key, key DESC, ...
+ } elseif ($mode === self::MODE_ORDER) { // key, key DESC, ...
foreach ($value as $k => $v) {
$vx[] = $this->delimite($k) . ($v > 0 ? '' : ' DESC');
}
@@ -267,11 +285,11 @@ private function formatValue($value, string $mode = null): string
throw new Nette\InvalidArgumentException("Unknown placeholder ?$mode.");
}
- } elseif (in_array($mode, self::MODE_LIST, true)) {
+ } elseif (in_array($mode, self::MODES, true)) {
$type = gettype($value);
throw new Nette\InvalidArgumentException("Placeholder ?$mode expects array or Traversable object, $type given.");
- } elseif ($mode && $mode !== 'auto') {
+ } elseif ($mode && $mode !== self::MODE_AUTO) {
throw new Nette\InvalidArgumentException("Unknown placeholder ?$mode.");
} else {
diff --git a/src/Database/Structure.php b/src/Database/Structure.php
index b2bc08ca4..5ec06790b 100644
--- a/src/Database/Structure.php
+++ b/src/Database/Structure.php
@@ -177,14 +177,11 @@ protected function needStructure(): void
return;
}
- $this->structure = $this->cache->load('structure', [$this, 'loadStructure']);
+ $this->structure = $this->cache->load('structure', \Closure::fromCallable([$this, 'loadStructure']));
}
- /**
- * @internal
- */
- public function loadStructure(): array
+ protected function loadStructure(): array
{
$driver = $this->connection->getSupplementalDriver();
diff --git a/tests/Database/Context.transaction.phpt b/tests/Database/Context.transaction.phpt
index c5d293845..b5f9f4a3e 100644
--- a/tests/Database/Context.transaction.phpt
+++ b/tests/Database/Context.transaction.phpt
@@ -23,6 +23,18 @@ test(function () use ($context) {
});
+test(function () use ($context) {
+ Assert::exception(function () use ($context) {
+ $context->transaction(function () use ($context) {
+ $context->query('DELETE FROM book');
+ throw new Exception('my exception');
+ });
+ }, Exception::class, 'my exception');
+
+ Assert::same(3, $context->fetchField('SELECT id FROM book WHERE id = ', 3));
+});
+
+
test(function () use ($context) {
$context->beginTransaction();
$context->query('DELETE FROM book');
diff --git a/tests/Database/SqlPreprocessor.phpt b/tests/Database/SqlPreprocessor.phpt
index d6cf7314d..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);
});
@@ -332,7 +337,7 @@ test(function () use ($preprocessor) { // insert
[$sql, $params] = $preprocessor->process(['/* comment */ INSERT INTO author',
['name' => 'Catelyn Stark'],
]);
- Assert::same(reformat("/* comment */ INSERT INTO author [name]='Catelyn Stark'"), $sql); // autodetection not used
+ Assert::same(reformat("/* comment */ INSERT INTO author 'Catelyn Stark'"), $sql); // autodetection not used
Assert::same([], $params);
});
@@ -347,10 +352,10 @@ test(function () use ($preprocessor) { // ?values
});
-test(function () use ($preprocessor) { // automatic detection faild
+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]]);
- }, 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]". Mode "values" was used.');
+ 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.');
});
@@ -440,10 +445,10 @@ test(function () use ($preprocessor) { // update
Assert::same([12, 'John Doe'], $params);
- [$sql, $params] = $preprocessor->process(['UPDATE author SET a=1,',
+ [$sql, $params] = $preprocessor->process(['UPDATE author SET a=1,', // autodetection not used
['id' => 12, 'name' => 'John Doe'],
]);
- Assert::same(reformat('UPDATE author SET a=1, [id]=?, [name]=?'), $sql);
+ Assert::same(reformat('UPDATE author SET a=1, ?, ?'), $sql);
Assert::same([12, 'John Doe'], $params);
});
|