Skip to content

Commit 152bc9e

Browse files
Ocramiusmorozov
authored andcommitted
Merge pull request #3369 from morozov/issues/3366
Handle binding errors in OCI8Statement::execute() and MySQLiStatement::execute()
2 parents 5f9c8fb + b7c7356 commit 152bc9e

File tree

5 files changed

+69
-32
lines changed

5 files changed

+69
-32
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+
## BC BREAK `Statement::execute()` with redundant parameters.
4+
5+
Similarly to the drivers based on `pdo_pgsql` and `pdo_sqlsrv`, `OCI8Statement::execute()` and `MySQLiStatement::execute()` do not longer ignore redundant parameters.
6+
37
## BC BREAK: `Doctrine\DBAL\Types\Type::getDefaultLength()` removed
48

59
The `Doctrine\DBAL\Types\Type::getDefaultLength()` method has been removed as it served no purpose.

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class MysqliStatement implements IteratorAggregate, Statement
4646
protected $_rowBindedValues;
4747

4848
/** @var mixed[] */
49-
protected $_bindedValues;
49+
protected $_bindedValues = [];
5050

5151
/** @var string */
5252
protected $types;
@@ -138,18 +138,18 @@ public function bindValue($param, $value, $type = ParameterType::STRING)
138138
*/
139139
public function execute($params = null)
140140
{
141-
if ($this->_bindedValues !== null) {
142-
if ($params !== null) {
143-
if (! $this->_bindValues($params)) {
144-
throw new MysqliException($this->_stmt->error, $this->_stmt->errno);
145-
}
146-
} else {
147-
[$types, $values, $streams] = $this->separateBoundValues();
148-
if (! $this->_stmt->bind_param($types, ...$values)) {
149-
throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno);
150-
}
151-
$this->sendLongData($streams);
141+
if ($params !== null && count($params) > 0) {
142+
if (! $this->_bindValues($params)) {
143+
throw new MysqliException($this->_stmt->error, $this->_stmt->errno);
152144
}
145+
} else {
146+
[$types, $values, $streams] = $this->separateBoundValues();
147+
148+
if (count($values) > 0 && ! $this->_stmt->bind_param($types, ...$values)) {
149+
throw new MysqliException($this->_stmt->error, $this->_stmt->sqlstate, $this->_stmt->errno);
150+
}
151+
152+
$this->sendLongData($streams);
153153
}
154154

155155
if (! $this->_stmt->execute()) {

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,13 @@ public function execute($params = null)
359359
$hasZeroIndex = array_key_exists(0, $params);
360360
foreach ($params as $key => $val) {
361361
if ($hasZeroIndex && is_numeric($key)) {
362-
$this->bindValue($key + 1, $val);
362+
$param = $key + 1;
363363
} else {
364-
$this->bindValue($key, $val);
364+
$param = $key;
365+
}
366+
367+
if (! $this->bindValue($param, $val)) {
368+
throw OCI8Exception::fromErrorInfo($this->errorInfo());
365369
}
366370
}
367371
}

tests/Doctrine/Tests/DBAL/Driver/OCI8/OCI8StatementTest.php

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,24 +41,15 @@ public function testExecute(array $params)
4141
->disableOriginalConstructor()
4242
->getMock();
4343

44-
$statement->expects($this->at(0))
45-
->method('bindValue')
46-
->with(
47-
$this->equalTo(1),
48-
$this->equalTo($params[0])
49-
);
50-
$statement->expects($this->at(1))
51-
->method('bindValue')
52-
->with(
53-
$this->equalTo(2),
54-
$this->equalTo($params[1])
55-
);
56-
$statement->expects($this->at(2))
57-
->method('bindValue')
58-
->with(
59-
$this->equalTo(3),
60-
$this->equalTo($params[2])
61-
);
44+
foreach ($params as $index => $value) {
45+
$statement->expects($this->at($index))
46+
->method('bindValue')
47+
->with(
48+
$this->equalTo($index + 1),
49+
$this->equalTo($value)
50+
)
51+
->willReturn(true);
52+
}
6253

6354
// can't pass to constructor since we don't have a real database handle,
6455
// but execute must check the connection for the executeMode

tests/Doctrine/Tests/DBAL/Functional/StatementTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Doctrine\Tests\DBAL\Functional;
44

5+
use Doctrine\DBAL\DBALException;
56
use Doctrine\DBAL\Driver\PDOOracle\Driver as PDOOracleDriver;
67
use Doctrine\DBAL\Driver\Statement;
78
use Doctrine\DBAL\FetchMode;
@@ -10,6 +11,7 @@
1011
use Doctrine\DBAL\Types\Type;
1112
use Doctrine\Tests\DbalFunctionalTestCase;
1213
use function base64_decode;
14+
use function sprintf;
1315
use function stream_get_contents;
1416

1517
class StatementTest extends DbalFunctionalTestCase
@@ -311,4 +313,40 @@ public function testFetchInColumnMode() : void
311313

312314
self::assertEquals(1, $result);
313315
}
316+
317+
public function testExecWithRedundantParameters() : void
318+
{
319+
$driver = $this->connection->getDriver()->getName();
320+
321+
switch ($driver) {
322+
case 'pdo_mysql':
323+
case 'pdo_oracle':
324+
case 'pdo_sqlsrv':
325+
self::markTestSkipped(sprintf(
326+
'PDOStatement::execute() implemented in the "%s" driver does not report redundant parameters',
327+
$driver
328+
));
329+
330+
return;
331+
case 'ibm_db2':
332+
self::markTestSkipped('db2_execute() does not report redundant parameters');
333+
334+
return;
335+
case 'sqlsrv':
336+
self::markTestSkipped('sqlsrv_prepare() does not report redundant parameters');
337+
338+
return;
339+
}
340+
341+
$platform = $this->connection->getDatabasePlatform();
342+
$query = $platform->getDummySelectSQL();
343+
$stmt = $this->connection->prepare($query);
344+
345+
// we want to make sure the exception is thrown by the DBAL code, not by PHPUnit due to a PHP-level error,
346+
// but the wrapper connection wraps everything in a DBAL exception
347+
$this->iniSet('error_reporting', 0);
348+
349+
self::expectException(DBALException::class);
350+
$stmt->execute([null]);
351+
}
314352
}

0 commit comments

Comments
 (0)