Skip to content

Commit 425bb79

Browse files
committed
fix: updateBatch() Postgre type error
1 parent f0fd848 commit 425bb79

File tree

4 files changed

+125
-21
lines changed

4 files changed

+125
-21
lines changed

system/Database/BaseBuilder.php

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ class BaseBuilder
130130
/**
131131
* QB data sets
132132
*
133-
* @var array<string, string>|list<list<int|string>>
133+
* @var array<string, string>|list<list<int|SqlValue|string>>
134134
*/
135135
protected $QBSet = [];
136136

@@ -1852,8 +1852,16 @@ public function setData($set, ?bool $escape = null, string $alias = '')
18521852

18531853
$clean = [];
18541854

1855-
foreach ($row as $rowValue) {
1856-
$clean[] = $escape ? $this->db->escape($rowValue) : $rowValue;
1855+
foreach ($row as $key => $rowValue) {
1856+
[$keyName, $keyType] = $this->parseKey($key);
1857+
1858+
$escapedValue = $escape ? $this->db->escape($rowValue) : $rowValue;
1859+
1860+
if ($keyType !== null) {
1861+
$clean[] = new SqlValue($escapedValue, $keyType);
1862+
} else {
1863+
$clean[] = $escapedValue;
1864+
}
18571865
}
18581866

18591867
$row = $clean;
@@ -1862,16 +1870,32 @@ public function setData($set, ?bool $escape = null, string $alias = '')
18621870
}
18631871

18641872
foreach ($keys as $k) {
1865-
$k = $this->db->protectIdentifiers($k, false);
1873+
[$keyName] = $this->parseKey($k);
18661874

1867-
if (! in_array($k, $this->QBKeys, true)) {
1868-
$this->QBKeys[] = $k;
1875+
$keyName = $this->db->protectIdentifiers($keyName, false);
1876+
1877+
if (! in_array($keyName, $this->QBKeys, true)) {
1878+
$this->QBKeys[] = $keyName;
18691879
}
18701880
}
18711881

18721882
return $this;
18731883
}
18741884

1885+
/**
1886+
* Parses column name (with type) and returns name and type
1887+
* Key examples:
1888+
* - 'updated_at::TIMESTAMP'
1889+
*/
1890+
private function parseKey(string $key): array
1891+
{
1892+
$keyInfo = explode('::', $key, 2);
1893+
$keyName = $keyInfo[0];
1894+
$keyType = $keyInfo[1] ?? null;
1895+
1896+
return [$keyName, $keyType];
1897+
}
1898+
18751899
/**
18761900
* Compiles an upsert query and returns the sql
18771901
*
@@ -2560,9 +2584,9 @@ public function updateBatch($set = null, $constraints = null, int $batchSize = 1
25602584
*
25612585
* @used-by batchExecute
25622586
*
2563-
* @param string $table Protected table name
2564-
* @param list<string> $keys QBKeys
2565-
* @param list<list<int|string>> $values QBSet
2587+
* @param string $table Protected table name
2588+
* @param list<string> $keys QBKeys
2589+
* @param list<list<int|SqlValue|string>> $values QBSet
25662590
*/
25672591
protected function _updateBatch(string $table, array $keys, array $values): string
25682592
{

system/Database/Postgre/Builder.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use CodeIgniter\Database\BaseBuilder;
1515
use CodeIgniter\Database\Exceptions\DatabaseException;
1616
use CodeIgniter\Database\RawSql;
17+
use CodeIgniter\Database\SqlValue;
1718
use InvalidArgumentException;
1819

1920
/**
@@ -317,9 +318,9 @@ public function join(string $table, $cond, string $type = '', ?bool $escape = nu
317318
*
318319
* @used-by batchExecute
319320
*
320-
* @param string $table Protected table name
321-
* @param list<string> $keys QBKeys
322-
* @param list<list<int|string>> $values QBSet
321+
* @param string $table Protected table name
322+
* @param list<string> $keys QBKeys
323+
* @param list<list<int|SqlValue|string>> $values QBSet
323324
*/
324325
protected function _updateBatch(string $table, array $keys, array $values): string
325326
{
@@ -393,7 +394,13 @@ protected function _updateBatch(string $table, array $keys, array $values): stri
393394
" UNION ALL\n",
394395
array_map(
395396
static fn ($value) => 'SELECT ' . implode(', ', array_map(
396-
static fn ($key, $index) => $index . ' ' . $key,
397+
static function ($key, $index) {
398+
if ($index instanceof SqlValue) {
399+
return $index->getValue() . '::' . $index->getType() . ' ' . $key;
400+
}
401+
402+
return $index . ' ' . $key;
403+
},
397404
$keys,
398405
$value
399406
)),

system/Database/SqlValue.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
/**
4+
* This file is part of CodeIgniter 4 framework.
5+
*
6+
* (c) CodeIgniter Foundation <admin@codeigniter.com>
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*/
11+
12+
namespace CodeIgniter\Database;
13+
14+
/**
15+
* @interal
16+
*/
17+
class SqlValue
18+
{
19+
/**
20+
* @var string Escaped column value.
21+
*/
22+
private string $value;
23+
24+
/**
25+
* @var string|null Column type.
26+
*/
27+
private ?string $type;
28+
29+
/**
30+
* @param string $value Escaped column value.
31+
* @param string|null $type Column type.
32+
*/
33+
public function __construct(string $value, ?string $type = null)
34+
{
35+
$this->value = $value;
36+
$this->type = $type;
37+
}
38+
39+
public function getValue(): string
40+
{
41+
return $this->value;
42+
}
43+
44+
public function getType(): string
45+
{
46+
return $this->type;
47+
}
48+
49+
public function __toString(): string
50+
{
51+
return $this->value;
52+
}
53+
}

tests/system/Database/Live/UpdateTest.php

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,24 +115,44 @@ public function testUpdateBatch(): void
115115
{
116116
$data = [
117117
[
118-
'name' => 'Derek Jones',
119-
'country' => 'Greece',
118+
'name' => 'Derek Jones',
119+
'country' => 'Greece',
120+
'updated_at' => '2023-12-02 18:47:52',
120121
],
121122
[
122-
'name' => 'Ahmadinejad',
123-
'country' => 'Greece',
123+
'name' => 'Ahmadinejad',
124+
'country' => 'Greece',
125+
'updated_at' => '2023-12-02 18:47:52',
124126
],
125127
];
126128

129+
if ($this->db->DBDriver === 'Postgre') {
130+
// PostgreSQL needs column type.
131+
$data = [
132+
[
133+
'name' => 'Derek Jones',
134+
'country' => 'Greece',
135+
'updated_at::TIMESTAMP' => '2023-12-02 18:47:52',
136+
],
137+
[
138+
'name' => 'Ahmadinejad',
139+
'country' => 'Greece',
140+
'updated_at::TIMESTAMP' => '2023-12-02 18:47:52',
141+
],
142+
];
143+
}
144+
127145
$this->db->table('user')->updateBatch($data, 'name');
128146

129147
$this->seeInDatabase('user', [
130-
'name' => 'Derek Jones',
131-
'country' => 'Greece',
148+
'name' => 'Derek Jones',
149+
'country' => 'Greece',
150+
'updated_at' => '2023-12-02 18:47:52',
132151
]);
133152
$this->seeInDatabase('user', [
134-
'name' => 'Ahmadinejad',
135-
'country' => 'Greece',
153+
'name' => 'Ahmadinejad',
154+
'country' => 'Greece',
155+
'updated_at' => '2023-12-02 18:47:52',
136156
]);
137157
}
138158

0 commit comments

Comments
 (0)