Skip to content

Commit 0ea989a

Browse files
committed
[Cache][Lock] Fix PDO store not creating table + add tests
1 parent 9c0a3a5 commit 0ea989a

File tree

4 files changed

+84
-26
lines changed

4 files changed

+84
-26
lines changed

Adapter/DoctrineDbalAdapter.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,8 @@ private function getServerVersion(): string
420420
return $this->serverVersion;
421421
}
422422

423-
$conn = $this->conn->getWrappedConnection();
423+
// The condition should be removed once support for DBAL <3.3 is dropped
424+
$conn = method_exists($this->conn, 'getNativeConnection') ? $this->conn->getNativeConnection() : $this->conn->getWrappedConnection();
424425
if ($conn instanceof ServerInfoAwareConnection) {
425426
return $this->serverVersion = $conn->getServerVersion();
426427
}

Adapter/PdoAdapter.php

Lines 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
}

Tests/Adapter/DoctrineDbalAdapterTest.php

Lines changed: 31 additions & 12 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,12 @@ public function testConfigureSchemaTableExists()
107104
}
108105

109106
/**
110-
* @dataProvider provideDsn
107+
* @dataProvider provideDsnWithSQLite
111108
*/
112-
public function testDsn(string $dsn, string $file = null)
109+
public function testDsnWithSQLite(string $dsn, string $file = null)
113110
{
114111
try {
115112
$pool = new DoctrineDbalAdapter($dsn);
116-
$pool->createTable();
117113

118114
$item = $pool->getItem('key');
119115
$item->set('value');
@@ -125,12 +121,35 @@ public function testDsn(string $dsn, string $file = null)
125121
}
126122
}
127123

128-
public static function provideDsn()
124+
public static function provideDsnWithSQLite()
129125
{
130126
$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:'];
127+
yield 'SQLite file' => ['sqlite://localhost/'.$dbFile.'1', $dbFile.'1'];
128+
yield 'SQLite3 file' => ['sqlite3:///'.$dbFile.'3', $dbFile.'3'];
129+
yield 'SQLite in memory' => ['sqlite://localhost/:memory:'];
130+
}
131+
132+
/**
133+
* @requires extension pdo_pgsql
134+
*
135+
* @group integration
136+
*/
137+
public function testDsnWithPostgreSQL()
138+
{
139+
if (!$host = getenv('POSTGRES_HOST')) {
140+
$this->markTestSkipped('Missing POSTGRES_HOST env variable');
141+
}
142+
143+
try {
144+
$pool = new DoctrineDbalAdapter('pgsql://postgres:password@'.$host);
145+
146+
$item = $pool->getItem('key');
147+
$item->set('value');
148+
$this->assertTrue($pool->save($item));
149+
} finally {
150+
$pdo = new \PDO('pgsql:host='.$host.';user=postgres;password=password');
151+
$pdo->exec('DROP TABLE IF EXISTS cache_items');
152+
}
134153
}
135154

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

Tests/Adapter/PdoAdapterTest.php

Lines changed: 32 additions & 11 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,12 @@ public function testCleanupExpiredItems()
7168
}
7269

7370
/**
74-
* @dataProvider provideDsn
71+
* @dataProvider provideDsnSQLite
7572
*/
76-
public function testDsn(string $dsn, string $file = null)
73+
public function testDsnWithSQLite(string $dsn, string $file = null)
7774
{
7875
try {
7976
$pool = new PdoAdapter($dsn);
80-
$pool->createTable();
8177

8278
$item = $pool->getItem('key');
8379
$item->set('value');
@@ -89,11 +85,36 @@ public function testDsn(string $dsn, string $file = null)
8985
}
9086
}
9187

92-
public static function provideDsn()
88+
public static function provideDsnSQLite()
9389
{
9490
$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
95-
yield ['sqlite:'.$dbFile.'2', $dbFile.'2'];
96-
yield ['sqlite::memory:'];
91+
yield 'SQLite file' => ['sqlite:'.$dbFile.'2', $dbFile.'2'];
92+
yield 'SQLite in memory' => ['sqlite::memory:'];
93+
}
94+
95+
/**
96+
* @requires extension pdo_pgsql
97+
*
98+
* @group integration
99+
*/
100+
public function testDsnWithPostgreSQL()
101+
{
102+
if (!$host = getenv('POSTGRES_HOST')) {
103+
$this->markTestSkipped('Missing POSTGRES_HOST env variable');
104+
}
105+
106+
$dsn = 'pgsql:host='.$host.';user=postgres;password=password';
107+
108+
try {
109+
$pool = new PdoAdapter($dsn);
110+
111+
$item = $pool->getItem('key');
112+
$item->set('value');
113+
$this->assertTrue($pool->save($item));
114+
} finally {
115+
$pdo = new \PDO($dsn);
116+
$pdo->exec('DROP TABLE IF EXISTS cache_items');
117+
}
97118
}
98119

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

0 commit comments

Comments
 (0)