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 0431dc3

Browse filesBrowse files
committed
[Cache][Lock] Fix PDO store not creating table + add tests
1 parent a454d0c commit 0431dc3
Copy full SHA for 0431dc3

File tree

6 files changed

+101
-31
lines changed
Filter options

6 files changed

+101
-31
lines changed

‎src/Symfony/Component/Cache/Adapter/PdoAdapter.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Adapter/PdoAdapter.php
+19-2Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ protected function doSave(array $values, int $lifetime)
507507
try {
508508
$stmt = $conn->prepare($sql);
509509
} catch (\PDOException $e) {
510-
if (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
510+
if ($this->isTableMissing($e) && (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true))) {
511511
$this->createTable();
512512
}
513513
$stmt = $conn->prepare($sql);
@@ -542,7 +542,7 @@ protected function doSave(array $values, int $lifetime)
542542
try {
543543
$stmt->execute();
544544
} catch (\PDOException $e) {
545-
if (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
545+
if ($this->isTableMissing($e) && (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true))) {
546546
$this->createTable();
547547
}
548548
$stmt->execute();
@@ -596,4 +596,21 @@ private function getServerVersion(): string
596596

597597
return $this->serverVersion;
598598
}
599+
600+
private function isTableMissing(\PDOException $exception): bool
601+
{
602+
$driver = $this->driver;
603+
$code = $exception->getCode();
604+
605+
switch (true) {
606+
case 'pgsql' === $driver && '42P01' === $code:
607+
case 'sqlite' === $driver && str_contains($exception->getMessage(), 'no such table:'):
608+
case 'oci' === $driver && 942 === $code:
609+
case 'sqlsrv' === $driver && 208 === $code:
610+
case 'mysql' === $driver && 1146 === $code:
611+
return true;
612+
default:
613+
return false;
614+
}
615+
}
599616
}

‎src/Symfony/Component/Cache/Tests/Adapter/DoctrineDbalAdapterTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Tests/Adapter/DoctrineDbalAdapterTest.php
+15-10Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
use Doctrine\DBAL\DriverManager;
1919
use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
2020
use Doctrine\DBAL\Schema\Schema;
21-
use PHPUnit\Framework\SkippedTestSuiteError;
2221
use Psr\Cache\CacheItemPoolInterface;
2322
use Symfony\Component\Cache\Adapter\DoctrineDbalAdapter;
2423
use Symfony\Component\Cache\Tests\Fixtures\DriverWrapper;
2524

2625
/**
26+
* @requires extension pdo_sqlite
27+
*
2728
* @group time-sensitive
2829
*/
2930
class DoctrineDbalAdapterTest extends AdapterTestCase
@@ -32,10 +33,6 @@ class DoctrineDbalAdapterTest extends AdapterTestCase
3233

3334
public static function setUpBeforeClass(): void
3435
{
35-
if (!\extension_loaded('pdo_sqlite')) {
36-
throw new SkippedTestSuiteError('Extension pdo_sqlite required.');
37-
}
38-
3936
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
4037
}
4138

@@ -107,13 +104,17 @@ public function testConfigureSchemaTableExists()
107104
}
108105

109106
/**
107+
* @group integration
108+
*
110109
* @dataProvider provideDsn
111110
*/
112-
public function testDsn(string $dsn, string $file = null)
111+
public function testDsn(string $dsn, string $pdoDsn, string $file = null)
113112
{
113+
$pdo = new \PDO($pdoDsn);
114+
$pdo->exec('DROP TABLE IF EXISTS cache_items');
115+
114116
try {
115117
$pool = new DoctrineDbalAdapter($dsn);
116-
$pool->createTable();
117118

118119
$item = $pool->getItem('key');
119120
$item->set('value');
@@ -128,9 +129,13 @@ public function testDsn(string $dsn, string $file = null)
128129
public static function provideDsn()
129130
{
130131
$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
131-
yield ['sqlite://localhost/'.$dbFile.'1', $dbFile.'1'];
132-
yield ['sqlite3:///'.$dbFile.'3', $dbFile.'3'];
133-
yield ['sqlite://localhost/:memory:'];
132+
yield 'SQLite file' => ['sqlite://localhost/'.$dbFile.'1', 'sqlite:'.$dbFile.'1', $dbFile.'1'];
133+
yield 'SQLite3 file' => ['sqlite3:///'.$dbFile.'3', 'sqlite:'.$dbFile.'3', $dbFile.'3'];
134+
yield 'SQLite in memory' => ['sqlite://localhost/:memory:', 'sqlite::memory:'];
135+
136+
if ($host = getenv('POSTGRES_HOST')) {
137+
yield 'PostgreSQL' => ['pgsql://postgres:password@'.$host, 'pgsql:host='.$host.';user=postgres;password=password'];
138+
}
134139
}
135140

136141
protected function isPruned(DoctrineDbalAdapter $cache, string $name): bool

‎src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Cache/Tests/Adapter/PdoAdapterTest.php
+13-8Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@
1111

1212
namespace Symfony\Component\Cache\Tests\Adapter;
1313

14-
use PHPUnit\Framework\SkippedTestSuiteError;
1514
use Psr\Cache\CacheItemPoolInterface;
1615
use Symfony\Component\Cache\Adapter\PdoAdapter;
1716

1817
/**
18+
* @requires extension pdo_sqlite
19+
*
1920
* @group time-sensitive
2021
*/
2122
class PdoAdapterTest extends AdapterTestCase
@@ -24,10 +25,6 @@ class PdoAdapterTest extends AdapterTestCase
2425

2526
public static function setUpBeforeClass(): void
2627
{
27-
if (!\extension_loaded('pdo_sqlite')) {
28-
throw new SkippedTestSuiteError('Extension pdo_sqlite required.');
29-
}
30-
3128
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
3229

3330
$pool = new PdoAdapter('sqlite:'.self::$dbFile);
@@ -71,13 +68,17 @@ public function testCleanupExpiredItems()
7168
}
7269

7370
/**
71+
* @group integration
72+
*
7473
* @dataProvider provideDsn
7574
*/
7675
public function testDsn(string $dsn, string $file = null)
7776
{
77+
$pdo = new \PDO($dsn);
78+
$pdo->exec('DROP TABLE IF EXISTS cache_items');
79+
7880
try {
7981
$pool = new PdoAdapter($dsn);
80-
$pool->createTable();
8182

8283
$item = $pool->getItem('key');
8384
$item->set('value');
@@ -92,8 +93,12 @@ public function testDsn(string $dsn, string $file = null)
9293
public static function provideDsn()
9394
{
9495
$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
95-
yield ['sqlite:'.$dbFile.'2', $dbFile.'2'];
96-
yield ['sqlite::memory:'];
96+
yield 'SQLite file' => ['sqlite:'.$dbFile.'2', $dbFile.'2'];
97+
yield 'SQLite in memory' =>['sqlite::memory:'];
98+
99+
if ($host = getenv('POSTGRES_HOST')) {
100+
yield 'PostgreSQL' => ['pgsql:host='.$host.';user=postgres;password=password'];
101+
}
97102
}
98103

99104
protected function isPruned(PdoAdapter $cache, string $name): bool

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Store/PdoStore.php
+30-3Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public function save(Key $key)
115115
try {
116116
$stmt = $conn->prepare($sql);
117117
} catch (\PDOException $e) {
118-
if (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) {
118+
if ($this->isTableMissing($e) && (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true))) {
119119
$this->createTable();
120120
}
121121
$stmt = $conn->prepare($sql);
@@ -127,8 +127,18 @@ public function save(Key $key)
127127
try {
128128
$stmt->execute();
129129
} catch (\PDOException $e) {
130-
// the lock is already acquired. It could be us. Let's try to put off.
131-
$this->putOffExpiration($key, $this->initialTtl);
130+
if ($this->isTableMissing($e) && (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true))) {
131+
$this->createTable();
132+
133+
try {
134+
$stmt->execute();
135+
} catch (\PDOException $e) {
136+
$this->putOffExpiration($key, $this->initialTtl);
137+
}
138+
} else {
139+
// the lock is already acquired. It could be us. Let's try to put off.
140+
$this->putOffExpiration($key, $this->initialTtl);
141+
}
132142
}
133143

134144
$this->randomlyPrune();
@@ -316,4 +326,21 @@ private function getCurrentTimestampStatement(): string
316326
return (string) time();
317327
}
318328
}
329+
330+
private function isTableMissing(\PDOException $exception): bool
331+
{
332+
$driver = $this->getDriver();
333+
$code = $exception->getCode();
334+
335+
switch (true) {
336+
case 'pgsql' === $driver && '42P01' === $code:
337+
case 'sqlite' === $driver && str_contains($exception->getMessage(), 'no such table:'):
338+
case 'oci' === $driver && 942 === $code:
339+
case 'sqlsrv' === $driver && 208 === $code:
340+
case 'mysql' === $driver && 1146 === $code:
341+
return true;
342+
default:
343+
return false;
344+
}
345+
}
319346
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Tests/Store/DoctrineDbalStoreTest.php
+13-4Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,15 @@ public function testAbortAfterExpiration()
7979
}
8080

8181
/**
82+
* @group integration
83+
*
8284
* @dataProvider provideDsn
8385
*/
84-
public function testDsn(string $dsn, string $file = null)
86+
public function testDsn(string $dsn, string $pdoDsn, string $file = null)
8587
{
88+
$pdo = new \PDO($pdoDsn);
89+
$pdo->exec('DROP TABLE IF EXISTS lock_keys');
90+
8691
$key = new Key(uniqid(__METHOD__, true));
8792

8893
try {
@@ -100,9 +105,13 @@ public function testDsn(string $dsn, string $file = null)
100105
public static function provideDsn()
101106
{
102107
$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
103-
yield ['sqlite://localhost/'.$dbFile.'1', $dbFile.'1'];
104-
yield ['sqlite3:///'.$dbFile.'3', $dbFile.'3'];
105-
yield ['sqlite://localhost/:memory:'];
108+
yield 'SQLite file' => ['sqlite://localhost/'.$dbFile.'1', 'sqlite:'.$dbFile.'1', $dbFile.'1'];
109+
yield 'SQLite3 file' => ['sqlite3:///'.$dbFile.'3', 'sqlite:'.$dbFile.'3', $dbFile.'3'];
110+
yield 'SQLite in memory' => ['sqlite://localhost/:memory:', 'sqlite::memory:'];
111+
112+
if ($host = getenv('POSTGRES_HOST')) {
113+
yield 'PostgreSQL' => ['pgsql://postgres:password@'.$host, 'pgsql:host='.$host.';user=postgres;password=password'];
114+
}
106115
}
107116

108117
/**

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Lock/Tests/Store/PdoStoreTest.php
+11-4Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
* @author Jérémy Derussé <jeremy@derusse.com>
2121
*
2222
* @requires extension pdo_sqlite
23-
*
24-
* @group integration
2523
*/
2624
class PdoStoreTest extends AbstractStoreTestCase
2725
{
@@ -78,10 +76,15 @@ public function testInvalidTtlConstruct()
7876
}
7977

8078
/**
79+
* @group integration
80+
*
8181
* @dataProvider provideDsn
8282
*/
8383
public function testDsn(string $dsn, string $file = null)
8484
{
85+
$pdo = new \PDO($dsn);
86+
$pdo->exec('DROP TABLE IF EXISTS lock_keys');
87+
8588
$key = new Key(uniqid(__METHOD__, true));
8689

8790
try {
@@ -99,7 +102,11 @@ public function testDsn(string $dsn, string $file = null)
99102
public static function provideDsn()
100103
{
101104
$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
102-
yield ['sqlite:'.$dbFile.'2', $dbFile.'2'];
103-
yield ['sqlite::memory:'];
105+
yield 'SQLite file' => ['sqlite:'.$dbFile.'2', $dbFile.'2'];
106+
yield 'SQLite in memory' => ['sqlite::memory:'];
107+
108+
if ($host = getenv('POSTGRES_HOST')) {
109+
yield 'PostgreSQL' => ['pgsql:host='.$host.';user=postgres;password=password'];
110+
}
104111
}
105112
}

0 commit comments

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