Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 83dbb47

Browse filesBrowse files
committed
bug #44383 [Lock] Create tables in transaction only if supported by driver (martinssipenko)
This PR was squashed before being merged into the 5.4 branch. Discussion ---------- [Lock] Create tables in transaction only if supported by driver | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | N/A | License | MIT | Doc PR | N/A Fixed `DoctrineDbalStore` to allow the creation of a lock table within a transaction only if it is supported by the driver. Commits ------- 9395de9 [Lock] Create tables in transaction only if supported by driver
2 parents ccd8014 + 9395de9 commit 83dbb47
Copy full SHA for 83dbb47

File tree

2 files changed

+161
-2
lines changed
Filter options

2 files changed

+161
-2
lines changed

‎src/Symfony/Component/Lock/Store/DoctrineDbalStore.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Store/DoctrineDbalStore.php
+34-2Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,21 @@ public function save(Key $key)
9292
ParameterType::STRING,
9393
]);
9494
} catch (TableNotFoundException $e) {
95-
$this->createTable();
96-
$this->save($key);
95+
if (!$this->conn->isTransactionActive() || $this->platformSupportsTableCreationInTransaction()) {
96+
$this->createTable();
97+
}
98+
99+
try {
100+
$this->conn->executeStatement($sql, [
101+
$this->getHashedKey($key),
102+
$this->getUniqueToken($key),
103+
], [
104+
ParameterType::STRING,
105+
ParameterType::STRING,
106+
]);
107+
} catch (DBALException $e) {
108+
$this->putOffExpiration($key, $this->initialTtl);
109+
}
97110
} catch (DBALException $e) {
98111
// the lock is already acquired. It could be us. Let's try to put off.
99112
$this->putOffExpiration($key, $this->initialTtl);
@@ -235,4 +248,23 @@ private function getCurrentTimestampStatement(): string
235248
return (string) time();
236249
}
237250
}
251+
252+
/**
253+
* Checks wether current platform supports table creation within transaction.
254+
*/
255+
private function platformSupportsTableCreationInTransaction(): bool
256+
{
257+
$platform = $this->conn->getDatabasePlatform();
258+
259+
switch (true) {
260+
case $platform instanceof \Doctrine\DBAL\Platforms\PostgreSQLPlatform:
261+
case $platform instanceof \Doctrine\DBAL\Platforms\PostgreSQL94Platform:
262+
case $platform instanceof \Doctrine\DBAL\Platforms\SqlitePlatform:
263+
case $platform instanceof \Doctrine\DBAL\Platforms\SQLServerPlatform:
264+
case $platform instanceof \Doctrine\DBAL\Platforms\SQLServer2012Platform:
265+
return true;
266+
default:
267+
return false;
268+
}
269+
}
238270
}

‎src/Symfony/Component/Lock/Tests/Store/DoctrineDbalStoreTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Tests/Store/DoctrineDbalStoreTest.php
+127Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@
1111

1212
namespace Symfony\Component\Lock\Tests\Store;
1313

14+
use Doctrine\DBAL\Connection;
1415
use Doctrine\DBAL\DriverManager;
16+
use Doctrine\DBAL\Exception\TableNotFoundException;
17+
use Doctrine\DBAL\Platforms\AbstractPlatform;
1518
use Symfony\Component\Lock\Key;
1619
use Symfony\Component\Lock\PersistingStoreInterface;
1720
use Symfony\Component\Lock\Store\DoctrineDbalStore;
1821

22+
class_exists(\Doctrine\DBAL\Platforms\PostgreSqlPlatform::class);
23+
1924
/**
2025
* @author Jérémy Derussé <jeremy@derusse.com>
2126
*
@@ -87,4 +92,126 @@ public function provideDsn()
8792
yield ['sqlite3:///'.$dbFile.'3', $dbFile.'3'];
8893
yield ['sqlite://localhost/:memory:'];
8994
}
95+
96+
/**
97+
* @dataProvider providePlatforms
98+
*/
99+
public function testCreatesTableInTransaction(string $platform)
100+
{
101+
$conn = $this->createMock(Connection::class);
102+
$conn->expects($this->exactly(3))
103+
->method('executeStatement')
104+
->withConsecutive(
105+
[$this->stringContains('INSERT INTO')],
106+
[$this->matches('create sql stmt')],
107+
[$this->stringContains('INSERT INTO')]
108+
)
109+
->will(
110+
$this->onConsecutiveCalls(
111+
$this->throwException(
112+
$this->createMock(TableNotFoundException::class)
113+
),
114+
1,
115+
1
116+
)
117+
);
118+
119+
$conn->method('isTransactionActive')
120+
->willReturn(true);
121+
122+
$platform = $this->createMock($platform);
123+
$platform->method('getCreateTableSQL')
124+
->willReturn(['create sql stmt']);
125+
126+
$conn->method('getDatabasePlatform')
127+
->willReturn($platform);
128+
129+
$store = new DoctrineDbalStore($conn);
130+
131+
$key = new Key(uniqid(__METHOD__, true));
132+
133+
$store->save($key);
134+
}
135+
136+
public function providePlatforms()
137+
{
138+
yield [\Doctrine\DBAL\Platforms\PostgreSQLPlatform::class];
139+
yield [\Doctrine\DBAL\Platforms\PostgreSQL94Platform::class];
140+
yield [\Doctrine\DBAL\Platforms\SqlitePlatform::class];
141+
yield [\Doctrine\DBAL\Platforms\SQLServerPlatform::class];
142+
yield [\Doctrine\DBAL\Platforms\SQLServer2012Platform::class];
143+
}
144+
145+
public function testTableCreationInTransactionNotSupported()
146+
{
147+
$conn = $this->createMock(Connection::class);
148+
$conn->expects($this->exactly(2))
149+
->method('executeStatement')
150+
->withConsecutive(
151+
[$this->stringContains('INSERT INTO')],
152+
[$this->stringContains('INSERT INTO')]
153+
)
154+
->will(
155+
$this->onConsecutiveCalls(
156+
$this->throwException(
157+
$this->createMock(TableNotFoundException::class)
158+
),
159+
1,
160+
1
161+
)
162+
);
163+
164+
$conn->method('isTransactionActive')
165+
->willReturn(true);
166+
167+
$platform = $this->createMock(AbstractPlatform::class);
168+
$platform->method('getCreateTableSQL')
169+
->willReturn(['create sql stmt']);
170+
171+
$conn->expects($this->exactly(2))
172+
->method('getDatabasePlatform');
173+
174+
$store = new DoctrineDbalStore($conn);
175+
176+
$key = new Key(uniqid(__METHOD__, true));
177+
178+
$store->save($key);
179+
}
180+
181+
public function testCreatesTableOutsideTransaction()
182+
{
183+
$conn = $this->createMock(Connection::class);
184+
$conn->expects($this->exactly(3))
185+
->method('executeStatement')
186+
->withConsecutive(
187+
[$this->stringContains('INSERT INTO')],
188+
[$this->matches('create sql stmt')],
189+
[$this->stringContains('INSERT INTO')]
190+
)
191+
->will(
192+
$this->onConsecutiveCalls(
193+
$this->throwException(
194+
$this->createMock(TableNotFoundException::class)
195+
),
196+
1,
197+
1
198+
)
199+
);
200+
201+
$conn->method('isTransactionActive')
202+
->willReturn(false);
203+
204+
$platform = $this->createMock(AbstractPlatform::class);
205+
$platform->method('getCreateTableSQL')
206+
->willReturn(['create sql stmt']);
207+
208+
$conn->method('getDatabasePlatform')
209+
->willReturn($platform);
210+
211+
$store = new DoctrineDbalStore($conn);
212+
213+
$key = new Key(uniqid(__METHOD__, true));
214+
215+
$store->save($key);
216+
}
90217
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.