Skip to content

Commit

Permalink
Fix batchInsert() with associative arrays (#242)
Browse files Browse the repository at this point in the history
* Fix `batchInsert()` with associative arrays

* Add line to CHANGELOG.md

---------

Co-authored-by: Sergei Predvoditelev <sergei@predvoditelev.ru>
  • Loading branch information
Tigrov and vjik committed Nov 12, 2023
1 parent e0bd00d commit 700e6ea
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,8 @@
- Bug #233: Refactor `DMLQueryBuilder`, related with yiisoft/db#746 (@Tigrov)
- Enh #230: Improve column type #230 (@Tigrov)
- Bug #240: Remove `RECURSIVE` expression from CTE queries (@Tigrov)
- Bug #242: Fix `AbstractDMLQueryBuilder::batchInsert()` for values as associative arrays,
related with yiisoft/db#769 (@Tigrov)
- Enh #243: Move methods from `Command` to `AbstractPdoCommand` class (@Tigrov)

## 1.1.0 July 24, 2023
Expand Down
26 changes: 16 additions & 10 deletions src/DMLQueryBuilder.php
Expand Up @@ -37,39 +37,45 @@ public function batchInsert(string $table, array $columns, iterable $rows, array

$values = [];
$columns = $this->getNormalizeColumnNames('', $columns);
$columnNames = array_values($columns);
$columnKeys = array_fill_keys($columnNames, false);
$columnSchemas = $this->schema->getTableSchema($table)?->getColumns() ?? [];

foreach ($rows as $row) {
$i = 0;
$placeholders = [];

foreach ($row as $value) {
if (isset($columns[$i], $columnSchemas[$columns[$i]])) {
$value = $columnSchemas[$columns[$i]]->dbTypecast($value);
$placeholders = $columnKeys;

foreach ($row as $key => $value) {
/** @psalm-suppress MixedArrayTypeCoercion */
$columnName = $columns[$key] ?? (isset($columnKeys[$key]) ? $key : $columnNames[$i] ?? $i);
/** @psalm-suppress MixedArrayTypeCoercion */
if (isset($columnSchemas[$columnName])) {
$value = $columnSchemas[$columnName]->dbTypecast($value);
}

if ($value instanceof ExpressionInterface) {
$placeholders[] = $this->queryBuilder->buildExpression($value, $params);
$placeholders[$columnName] = $this->queryBuilder->buildExpression($value, $params);
} else {
$placeholders[] = $this->queryBuilder->bindParam($value, $params);
$placeholders[$columnName] = $this->queryBuilder->bindParam($value, $params);
}

++$i;
}

$values[] = '(' . implode(', ', $placeholders) . ')';
}

if (empty($values)) {
return '';
}

$columns = array_map(
$columnNames = array_map(
[$this->quoter, 'quoteColumnName'],
$columns,
$columnNames,
);

$tableAndColumns = ' INTO ' . $this->quoter->quoteTableName($table)
. ' (' . implode(', ', $columns) . ') VALUES ';
. ' (' . implode(', ', $columnNames) . ') VALUES ';

return 'INSERT ALL ' . $tableAndColumns . implode($tableAndColumns, $values) . ' SELECT 1 FROM SYS.DUAL';
}
Expand Down
41 changes: 31 additions & 10 deletions tests/Provider/CommandProvider.php
Expand Up @@ -10,6 +10,7 @@
use Yiisoft\Db\Oracle\Tests\Support\TestTrait;
use Yiisoft\Db\Tests\Support\DbHelper;

use function array_merge;
use function json_encode;
use function serialize;

Expand All @@ -29,17 +30,37 @@ public static function batchInsert(): array
$batchInsert['multirow']['expectedParams'][':qp3'] = '1';
$batchInsert['multirow']['expectedParams'][':qp7'] = '0';

DbHelper::changeSqlForOracleBatchInsert($batchInsert['issue11242']['expected']);
$batchInsert['issue11242']['expectedParams'][':qp3'] = '1';

DbHelper::changeSqlForOracleBatchInsert($batchInsert['table name with column name with brackets']['expected']);
$batchInsert['table name with column name with brackets']['expectedParams'][':qp3'] = '0';

DbHelper::changeSqlForOracleBatchInsert($batchInsert['batchInsert binds params from expression']['expected']);
$batchInsert['batchInsert binds params from expression']['expectedParams'][':qp3'] = '0';
$replaceParams = [
'issue11242' => [
':qp3' => '1',
],
'table name with column name with brackets' => [
':qp3' => '0',
],
'batchInsert binds params from expression' => [
':qp3' => '0',
],
'with associative values with different keys' => [
':qp3' => '1',
],
'with associative values with different keys and columns with keys' => [
':qp3' => '1',
],
'with associative values with keys of column names' => [
':qp0' => '1',
],
'with associative values with keys of column keys' => [
':qp0' => '1',
],
'with shuffled indexes of values' => [
':qp0' => '1',
],
];

DbHelper::changeSqlForOracleBatchInsert($batchInsert['with associative values']['expected']);
$batchInsert['with associative values']['expectedParams'][':qp3'] = '1';
foreach ($replaceParams as $key => $expectedParams) {
DbHelper::changeSqlForOracleBatchInsert($batchInsert[$key]['expected']);
$batchInsert[$key]['expectedParams'] = array_merge($batchInsert[$key]['expectedParams'], $expectedParams);
}

return $batchInsert;
}
Expand Down

0 comments on commit 700e6ea

Please sign in to comment.