Skip to content

Commit

Permalink
Connection: Support IS NULL in update/delete criteria
Browse files Browse the repository at this point in the history
If you pass a null to the where array of update or delete it's
pretty obvious what you want.

Most (all?) databases won't match anything if you actually try
to compare with NULL making this a silent failure without it.
  • Loading branch information
jnvsor committed Mar 27, 2017
1 parent e0169b2 commit 8e6e090
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 10 deletions.
33 changes: 23 additions & 10 deletions lib/Doctrine/DBAL/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,27 @@ public function isTransactionActive()
return $this->_transactionNestingLevel > 0;
}

/**
* Sets criteria for an update or delete call.
*
* @param array $identifiers Input array of columns to values
* @param array &$columnList Output list of bound columns for extractTypeValues
* @param array &$criteria Output array of criteria
* @param array &$paramValues Output bound values
*/
protected function setCriteria($identifiers, &$columnList, &$criteria, &$paramValues)
{
foreach ($identifiers as $columnName => $value) {
if (is_null($value)) {
$criteria[] = $this->getDatabasePlatform()->getIsNullExpression($columnName);
} else {
$columnList[] = $columnName;
$paramValues[] = $value;
$criteria[] = $columnName . ' = ?';
}
}
}

/**
* Executes an SQL DELETE statement on a table.
*
Expand All @@ -583,11 +604,7 @@ public function delete($tableExpression, array $identifier, array $types = array
$criteria = array();
$paramValues = array();

foreach ($identifier as $columnName => $value) {
$columnList[] = $columnName;
$criteria[] = $columnName . ' = ?';
$paramValues[] = $value;
}
$this->setCriteria($identifier, $columnList, $criteria, $paramValues);

return $this->executeUpdate(
'DELETE FROM ' . $tableExpression . ' WHERE ' . implode(' AND ', $criteria),
Expand Down Expand Up @@ -661,11 +678,7 @@ public function update($tableExpression, array $data, array $identifier, array $
$paramValues[] = $value;
}

foreach ($identifier as $columnName => $value) {
$columnList[] = $columnName;
$criteria[] = $columnName . ' = ?';
$paramValues[] = $value;
}
$this->setCriteria($identifier, $columnList, $criteria, $paramValues);

if (is_string(key($types))) {
$types = $this->extractTypeValues($columnList, $types);
Expand Down
92 changes: 92 additions & 0 deletions tests/Doctrine/Tests/DBAL/ConnectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,98 @@ public function testUpdateWithSameColumnInDataAndIdentifiers()
);
}

/**
* @group DBAL-2688
*/
public function testUpdateWithIsNull()
{
$driverMock = $this->createMock('Doctrine\DBAL\Driver');

$driverMock->expects($this->any())
->method('connect')
->will($this->returnValue(new DriverConnectionMock()));

$conn = $this->getMockBuilder('Doctrine\DBAL\Connection')
->setMethods(array('executeUpdate'))
->setConstructorArgs(array(array('platform' => new Mocks\MockPlatform()), $driverMock))
->getMock();

$conn->expects($this->once())
->method('executeUpdate')
->with(
'UPDATE TestTable SET text = ?, is_edited = ? WHERE id IS NULL AND name = ?',
[
'some text',
null,
'foo',
],
[
'string',
'null',
'string',
]
);

$conn->update(
'TestTable',
[
'text' => 'some text',
'is_edited' => null,
],
[
'id' => null,
'name' => 'foo',
],
[
'text' => 'string',
'is_edited' => 'null',
'id' => 'null',
'name' => 'string',
]
);
}

/**
* @group DBAL-2688
*/
public function testDeleteWithIsNull()
{
$driverMock = $this->createMock('Doctrine\DBAL\Driver');

$driverMock->expects($this->any())
->method('connect')
->will($this->returnValue(new DriverConnectionMock()));

$conn = $this->getMockBuilder('Doctrine\DBAL\Connection')
->setMethods(array('executeUpdate'))
->setConstructorArgs(array(array('platform' => new Mocks\MockPlatform()), $driverMock))
->getMock();

$conn->expects($this->once())
->method('executeUpdate')
->with(
'DELETE FROM TestTable WHERE id IS NULL AND name = ?',
[
'foo',
],
[
'string',
]
);

$conn->delete(
'TestTable',
[
'id' => null,
'name' => 'foo',
],
[
'id' => 'null',
'name' => 'string',
]
);
}

public function testFetchAssoc()
{
$statement = 'SELECT * FROM foo WHERE bar = ?';
Expand Down

0 comments on commit 8e6e090

Please sign in to comment.