Skip to content

Commit cfd1c33

Browse files
committed
Merge pull request #3417 from morozov/issues/3358
Statement::fetchColumn() will throw an exception in the case of invalid index
2 parents 968d971 + 3d912ba commit cfd1c33

File tree

12 files changed

+115
-10
lines changed

12 files changed

+115
-10
lines changed

UPGRADE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Upgrade to 3.0
22

3+
## MINOR BC BREAK `Statement::fetchColumn()` with an invalid index.
4+
5+
Similarly to `PDOStatement::fetchColumn()`, DBAL statements throw an exception in case of an invalid column index.
6+
37
## BC BREAK `Statement::execute()` with redundant parameters.
48

59
Similarly to the drivers based on `pdo_pgsql` and `pdo_sqlsrv`, `OCI8Statement::execute()` and `MySQLiStatement::execute()` do not longer ignore redundant parameters.

lib/Doctrine/DBAL/Cache/ArrayStatement.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
namespace Doctrine\DBAL\Cache;
44

55
use ArrayIterator;
6+
use Doctrine\DBAL\DBALException;
67
use Doctrine\DBAL\Driver\ResultStatement;
78
use Doctrine\DBAL\FetchMode;
89
use InvalidArgumentException;
910
use IteratorAggregate;
11+
use function array_key_exists;
1012
use function array_merge;
1113
use function array_values;
1214
use function count;
@@ -130,7 +132,14 @@ public function fetchColumn($columnIndex = 0)
130132
{
131133
$row = $this->fetch(FetchMode::NUMERIC);
132134

133-
// TODO: verify that return false is the correct behavior
134-
return $row[$columnIndex] ?? false;
135+
if ($row === false) {
136+
return false;
137+
}
138+
139+
if (! array_key_exists($columnIndex, $row)) {
140+
throw DBALException::invalidColumnIndex($columnIndex, count($row));
141+
}
142+
143+
return $row[$columnIndex];
135144
}
136145
}

lib/Doctrine/DBAL/Cache/ResultCacheStatement.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44

55
use ArrayIterator;
66
use Doctrine\Common\Cache\Cache;
7+
use Doctrine\DBAL\DBALException;
78
use Doctrine\DBAL\Driver\ResultStatement;
89
use Doctrine\DBAL\Driver\Statement;
910
use Doctrine\DBAL\FetchMode;
1011
use InvalidArgumentException;
1112
use IteratorAggregate;
13+
use function array_key_exists;
1214
use function array_merge;
1315
use function array_values;
1416
use function assert;
17+
use function count;
1518
use function reset;
1619

1720
/**
@@ -179,8 +182,15 @@ public function fetchColumn($columnIndex = 0)
179182
{
180183
$row = $this->fetch(FetchMode::NUMERIC);
181184

182-
// TODO: verify that return false is the correct behavior
183-
return $row[$columnIndex] ?? false;
185+
if ($row === false) {
186+
return false;
187+
}
188+
189+
if (! array_key_exists($columnIndex, $row)) {
190+
throw DBALException::invalidColumnIndex($columnIndex, count($row));
191+
}
192+
193+
return $row[$columnIndex];
184194
}
185195

186196
/**

lib/Doctrine/DBAL/DBALException.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,4 +291,14 @@ public static function typeAlreadyRegistered(Type $type) : self
291291
sprintf('Type of the class %s@%s is already registered.', get_class($type), spl_object_hash($type))
292292
);
293293
}
294+
295+
public static function invalidColumnIndex(int $index, int $count) : self
296+
{
297+
return new self(sprintf(
298+
'Invalid column index %d. The statement result contains %d column%s.',
299+
$index,
300+
$count,
301+
$count === 1 ? '' : 's'
302+
));
303+
}
294304
}

lib/Doctrine/DBAL/Driver/IBMDB2/DB2Statement.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Doctrine\DBAL\Driver\IBMDB2;
44

5+
use Doctrine\DBAL\DBALException;
56
use Doctrine\DBAL\Driver\Statement;
67
use Doctrine\DBAL\Driver\StatementIterator;
78
use Doctrine\DBAL\FetchMode;
@@ -18,6 +19,7 @@
1819
use const DB2_PARAM_FILE;
1920
use const DB2_PARAM_IN;
2021
use function array_change_key_case;
22+
use function array_key_exists;
2123
use function count;
2224
use function db2_bind_param;
2325
use function db2_execute;
@@ -338,7 +340,11 @@ public function fetchColumn($columnIndex = 0)
338340
return false;
339341
}
340342

341-
return $row[$columnIndex] ?? null;
343+
if (! array_key_exists($columnIndex, $row)) {
344+
throw DBALException::invalidColumnIndex($columnIndex, count($row));
345+
}
346+
347+
return $row[$columnIndex];
342348
}
343349

344350
/**

lib/Doctrine/DBAL/Driver/Mysqli/MysqliStatement.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Doctrine\DBAL\Driver\Mysqli;
44

5+
use Doctrine\DBAL\DBALException;
56
use Doctrine\DBAL\Driver\Statement;
67
use Doctrine\DBAL\Driver\StatementIterator;
78
use Doctrine\DBAL\Exception\InvalidArgumentException;
@@ -12,6 +13,7 @@
1213
use mysqli_stmt;
1314
use function array_combine;
1415
use function array_fill;
16+
use function array_key_exists;
1517
use function assert;
1618
use function count;
1719
use function feof;
@@ -380,7 +382,11 @@ public function fetchColumn($columnIndex = 0)
380382
return false;
381383
}
382384

383-
return $row[$columnIndex] ?? null;
385+
if (! array_key_exists($columnIndex, $row)) {
386+
throw DBALException::invalidColumnIndex($columnIndex, count($row));
387+
}
388+
389+
return $row[$columnIndex];
384390
}
385391

386392
/**

lib/Doctrine/DBAL/Driver/OCI8/OCI8Statement.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Doctrine\DBAL\Driver\OCI8;
44

5+
use Doctrine\DBAL\DBALException;
56
use Doctrine\DBAL\Driver\Statement;
67
use Doctrine\DBAL\Driver\StatementIterator;
78
use Doctrine\DBAL\FetchMode;
@@ -517,7 +518,11 @@ public function fetchColumn($columnIndex = 0)
517518
return false;
518519
}
519520

520-
return $row[$columnIndex] ?? null;
521+
if (! array_key_exists($columnIndex, $row)) {
522+
throw DBALException::invalidColumnIndex($columnIndex, count($row));
523+
}
524+
525+
return $row[$columnIndex];
521526
}
522527

523528
/**

lib/Doctrine/DBAL/Driver/PDOStatement.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Doctrine\DBAL\Driver;
44

5+
use Doctrine\DBAL\DBALException;
56
use Doctrine\DBAL\FetchMode;
67
use Doctrine\DBAL\ParameterType;
78
use IteratorAggregate;
@@ -193,7 +194,17 @@ public function fetchAll($fetchMode = null, ...$args)
193194
public function fetchColumn($columnIndex = 0)
194195
{
195196
try {
196-
return $this->stmt->fetchColumn($columnIndex);
197+
$value = $this->stmt->fetchColumn($columnIndex);
198+
199+
if ($value === null) {
200+
$columnCount = $this->columnCount();
201+
202+
if ($columnIndex < 0 || $columnIndex >= $columnCount) {
203+
throw DBALException::invalidColumnIndex($columnIndex, $columnCount);
204+
}
205+
}
206+
207+
return $value;
197208
} catch (\PDOException $exception) {
198209
throw new PDOException($exception);
199210
}

lib/Doctrine/DBAL/Driver/SQLAnywhere/SQLAnywhereStatement.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Doctrine\DBAL\Driver\SQLAnywhere;
44

5+
use Doctrine\DBAL\DBALException;
56
use Doctrine\DBAL\Driver\Statement;
67
use Doctrine\DBAL\Driver\StatementIterator;
78
use Doctrine\DBAL\FetchMode;
@@ -284,7 +285,9 @@ public function fetchColumn($columnIndex = 0)
284285
return false;
285286
}
286287

287-
return $row[$columnIndex] ?? null;
288+
if (! array_key_exists($columnIndex, $row)) {
289+
throw DBALException::invalidColumnIndex($columnIndex, count($row));
290+
}
288291
}
289292

290293
/**

lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvStatement.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Doctrine\DBAL\Driver\SQLSrv;
44

5+
use Doctrine\DBAL\DBALException;
56
use Doctrine\DBAL\Driver\Statement;
67
use Doctrine\DBAL\Driver\StatementIterator;
78
use Doctrine\DBAL\FetchMode;
@@ -412,7 +413,11 @@ public function fetchColumn($columnIndex = 0)
412413
return false;
413414
}
414415

415-
return $row[$columnIndex] ?? null;
416+
if (! array_key_exists($columnIndex, $row)) {
417+
throw DBALException::invalidColumnIndex($columnIndex, count($row));
418+
}
419+
420+
return $row[$columnIndex];
416421
}
417422

418423
/**

0 commit comments

Comments
 (0)