Skip to content

Commit 74bc147

Browse files
authored
Merge pull request #4400 from BenMorel/with-nolock
LockMode::NONE should not set WITH (NOLOCK)
2 parents 5f94000 + 3ed11aa commit 74bc147

File tree

7 files changed

+109
-8
lines changed

7 files changed

+109
-8
lines changed

lib/Doctrine/DBAL/Platforms/SQLAnywherePlatform.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function appendLockHint($fromClause, $lockMode)
5252
{
5353
switch (true) {
5454
case $lockMode === LockMode::NONE:
55-
return $fromClause . ' WITH (NOLOCK)';
55+
return $fromClause;
5656

5757
case $lockMode === LockMode::PESSIMISTIC_READ:
5858
return $fromClause . ' WITH (UPDLOCK)';

lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1574,7 +1574,7 @@ public function appendLockHint($fromClause, $lockMode)
15741574
{
15751575
switch (true) {
15761576
case $lockMode === LockMode::NONE:
1577-
return $fromClause . ' WITH (NOLOCK)';
1577+
return $fromClause;
15781578

15791579
case $lockMode === LockMode::PESSIMISTIC_READ:
15801580
return $fromClause . ' WITH (HOLDLOCK, ROWLOCK)';
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\Tests\DBAL\Functional\LockMode;
6+
7+
use Doctrine\DBAL\Connection;
8+
use Doctrine\DBAL\Driver\OCI8;
9+
use Doctrine\DBAL\Exception;
10+
use Doctrine\DBAL\LockMode;
11+
use Doctrine\DBAL\Platforms\SqlitePlatform;
12+
use Doctrine\DBAL\Platforms\SQLServerPlatform;
13+
use Doctrine\DBAL\Schema\Table;
14+
use Doctrine\DBAL\TransactionIsolationLevel;
15+
use Doctrine\Tests\DbalFunctionalTestCase;
16+
use Doctrine\Tests\TestUtil;
17+
18+
class NoneTest extends DbalFunctionalTestCase
19+
{
20+
/** @var Connection */
21+
private $connection2;
22+
23+
public function setUp(): void
24+
{
25+
parent::setUp();
26+
27+
if ($this->connection->getDriver() instanceof OCI8\Driver) {
28+
// https://github.com/doctrine/dbal/issues/4417
29+
self::markTestSkipped('This test fails on OCI8 for a currently unknown reason');
30+
}
31+
32+
if ($this->connection->getDatabasePlatform() instanceof SQLServerPlatform) {
33+
// Use row versioning instead of locking on SQL Server (if we don't, the second connection will block when
34+
// attempting to read the row created by the first connection, instead of reading the previous version);
35+
// for some reason we cannot set READ_COMMITTED_SNAPSHOT ON when not running this test in isolation,
36+
// there may be another connection active at this point; temporarily forcing to SINGLE_USER does the trick.
37+
$db = $this->connection->getDatabase();
38+
$this->connection->executeStatement('ALTER DATABASE ' . $db . ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE');
39+
$this->connection->executeStatement('ALTER DATABASE ' . $db . ' SET READ_COMMITTED_SNAPSHOT ON');
40+
$this->connection->executeStatement('ALTER DATABASE ' . $db . ' SET MULTI_USER');
41+
}
42+
43+
$table = new Table('users');
44+
$table->addColumn('id', 'integer');
45+
$table->setPrimaryKey(['id']);
46+
47+
$this->connection->getSchemaManager()->dropAndCreateTable($table);
48+
49+
$this->connection2 = TestUtil::getConnection();
50+
51+
if ($this->connection2->getSchemaManager()->tablesExist('users')) {
52+
return;
53+
}
54+
55+
if ($this->connection2->getDatabasePlatform() instanceof SqlitePlatform) {
56+
self::markTestSkipped('This test cannot run on SQLite using an in-memory database');
57+
}
58+
59+
self::fail('Separate connections do not seem to talk to the same database');
60+
}
61+
62+
public function tearDown(): void
63+
{
64+
parent::tearDown();
65+
66+
if ($this->connection2->isTransactionActive()) {
67+
$this->connection2->rollBack();
68+
}
69+
70+
$this->connection2->close();
71+
72+
$this->connection->getSchemaManager()->dropTable('users');
73+
74+
if (! $this->connection->getDatabasePlatform() instanceof SQLServerPlatform) {
75+
return;
76+
}
77+
78+
$db = $this->connection->getDatabase();
79+
$this->connection->executeStatement('ALTER DATABASE ' . $db . ' SET READ_COMMITTED_SNAPSHOT OFF');
80+
}
81+
82+
public function testLockModeNoneDoesNotBreakTransactionIsolation(): void
83+
{
84+
try {
85+
$this->connection->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED);
86+
$this->connection2->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED);
87+
} catch (Exception $e) {
88+
self::markTestSkipped('This test must be able to set a transaction isolation level');
89+
}
90+
91+
$this->connection->beginTransaction();
92+
$this->connection2->beginTransaction();
93+
94+
$this->connection->insert('users', ['id' => 1]);
95+
96+
$query = 'SELECT id FROM users';
97+
$query = $this->connection2->getDatabasePlatform()->appendLockHint($query, LockMode::NONE);
98+
99+
self::assertFalse($this->connection2->fetchOne($query));
100+
}
101+
}

tests/Doctrine/Tests/DBAL/Platforms/AbstractSQLServerPlatformTestCase.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,14 +374,14 @@ public function testModifyLimitQueryWithOrderByClause(): void
374374
}
375375

376376
$sql = 'SELECT m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2'
377-
. ' FROM MEDICION m0_ WITH (NOLOCK)'
377+
. ' FROM MEDICION m0_'
378378
. ' INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID'
379379
. ' INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID'
380380
. ' INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID'
381381
. ' WHERE u3_.ID = ? ORDER BY m0_.FECHAINICIO DESC';
382382

383383
$alteredSql = 'SELECT TOP 15 m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2'
384-
. ' FROM MEDICION m0_ WITH (NOLOCK)'
384+
. ' FROM MEDICION m0_'
385385
. ' INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID'
386386
. ' INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID'
387387
. ' INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID'

tests/Doctrine/Tests/DBAL/Platforms/SQLAnywherePlatformTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ public static function getLockHints(): iterable
266266
[null, ''],
267267
[false, ''],
268268
[true, ''],
269-
[LockMode::NONE, ' WITH (NOLOCK)'],
269+
[LockMode::NONE, ''],
270270
[LockMode::OPTIMISTIC, ''],
271271
[LockMode::PESSIMISTIC_READ, ' WITH (UPDLOCK)'],
272272
[LockMode::PESSIMISTIC_WRITE, ' WITH (XLOCK)'],

tests/Doctrine/Tests/DBAL/Platforms/SQLServer2012PlatformTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,14 +224,14 @@ public function testModifyLimitQueryWithExtraLongQuery(): void
224224
public function testModifyLimitQueryWithOrderByClause(): void
225225
{
226226
$sql = 'SELECT m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2'
227-
. ' FROM MEDICION m0_ WITH (NOLOCK)'
227+
. ' FROM MEDICION m0_'
228228
. ' INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID'
229229
. ' INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID'
230230
. ' INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID'
231231
. ' WHERE u3_.ID = ? ORDER BY m0_.FECHAINICIO DESC';
232232

233233
$expected = 'SELECT m0_.NOMBRE AS NOMBRE0, m0_.FECHAINICIO AS FECHAINICIO1, m0_.FECHAFIN AS FECHAFIN2'
234-
. ' FROM MEDICION m0_ WITH (NOLOCK)'
234+
. ' FROM MEDICION m0_'
235235
. ' INNER JOIN ESTUDIO e1_ ON m0_.ESTUDIO_ID = e1_.ID'
236236
. ' INNER JOIN CLIENTE c2_ ON e1_.CLIENTE_ID = c2_.ID'
237237
. ' INNER JOIN USUARIO u3_ ON c2_.ID = u3_.CLIENTE_ID'

tests/Doctrine/Tests/DBAL/Platforms/SQLServerPlatformTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public static function getLockHints(): iterable
3939
{
4040
return [
4141
[null, ''],
42-
[LockMode::NONE, ' WITH (NOLOCK)'],
42+
[LockMode::NONE, ''],
4343
[LockMode::OPTIMISTIC, ''],
4444
[LockMode::PESSIMISTIC_READ, ' WITH (HOLDLOCK, ROWLOCK)'],
4545
[LockMode::PESSIMISTIC_WRITE, ' WITH (UPDLOCK, ROWLOCK)'],

0 commit comments

Comments
 (0)