Browse Source

Add support for opening sqlite db with shared cache

Corey Taylor 4 years ago
parent
commit
209733894c
2 changed files with 66 additions and 5 deletions
  1. 25 4
      src/Database/Driver/Sqlite.php
  2. 41 1
      tests/TestCase/Database/Driver/SqliteTest.php

+ 25 - 4
src/Database/Driver/Sqlite.php

@@ -29,6 +29,7 @@ use Cake\Database\Statement\SqliteStatement;
 use Cake\Database\StatementInterface;
 use InvalidArgumentException;
 use PDO;
+use RuntimeException;
 
 /**
  * Class Sqlite
@@ -52,6 +53,8 @@ class Sqlite extends Driver
         'database' => ':memory:',
         'encoding' => 'utf8',
         'mask' => 0644,
+        'cache' => null,
+        'mode' => null,
         'flags' => [],
         'init' => [],
     ];
@@ -132,12 +135,30 @@ class Sqlite extends Driver
             );
         }
 
-        $databaseExists = file_exists($config['database']);
+        $chmodFile = false;
+        if ($config['database'] !== ':memory:' && $config['mode'] !== 'memory') {
+            $chmodFile = !file_exists($config['database']);
+        }
 
-        $dsn = "sqlite:{$config['database']}";
-        $this->_connect($dsn, $config);
+        $params = [];
+        if ($config['cache']) {
+            $params[] = 'cache=' . $config['cache'];
+        }
+        if ($config['mode']) {
+            $params[] = 'mode=' . $config['mode'];
+        }
 
-        if (!$databaseExists && $config['database'] !== ':memory:') {
+        if ($params) {
+            if (PHP_VERSION_ID < 80100) {
+                throw new RuntimeException('SQLite URI support requires PHP 8.1.');
+            }
+            $dsn = 'sqlite:file:' . $config['database'] . '?' . implode('&', $params);
+        } else {
+            $dsn = 'sqlite:' . $config['database'];
+        }
+
+        $this->_connect($dsn, $config);
+        if ($chmodFile) {
             // phpcs:disable
             @chmod($config['database'], $config['mask']);
             // phpcs:enable

+ 41 - 1
tests/TestCase/Database/Driver/SqliteTest.php

@@ -16,6 +16,7 @@ declare(strict_types=1);
  */
 namespace Cake\Test\TestCase\Database\Driver;
 
+use Cake\Database\Connection;
 use Cake\Database\Driver\Sqlite;
 use Cake\Database\DriverInterface;
 use Cake\Datasource\ConnectionManager;
@@ -27,6 +28,13 @@ use PDO;
  */
 class SqliteTest extends TestCase
 {
+    public function tearDown(): void
+    {
+        parent::tearDown();
+        ConnectionManager::drop('test_shared_cache');
+        ConnectionManager::drop('test_shared_cache2');
+    }
+
     /**
      * Test connecting to Sqlite with default configuration
      */
@@ -40,6 +48,8 @@ class SqliteTest extends TestCase
             'persistent' => false,
             'database' => ':memory:',
             'encoding' => 'utf8',
+            'cache' => null,
+            'mode' => null,
             'username' => null,
             'password' => null,
             'flags' => [],
@@ -78,7 +88,7 @@ class SqliteTest extends TestCase
         $dsn = 'sqlite:bar.db';
 
         $expected = $config;
-        $expected += ['username' => null, 'password' => null];
+        $expected += ['username' => null, 'password' => null, 'cache' => null, 'mode' => null];
         $expected['flags'] += [
             PDO::ATTR_PERSISTENT => true,
             PDO::ATTR_EMULATE_PREPARES => false,
@@ -100,6 +110,36 @@ class SqliteTest extends TestCase
     }
 
     /**
+     * Tests creating multiple connections to same db.
+     */
+    public function testConnectionSharedCached()
+    {
+        $this->skipIf(PHP_VERSION_ID < 80100 || !extension_loaded('pdo_sqlite'), 'Skipping as SQLite extension is missing');
+        ConnectionManager::setConfig('test_shared_cache', [
+            'className' => Connection::class,
+            'driver' => Sqlite::class,
+            'database' => ':memory:',
+            'cache' => 'shared',
+        ]);
+
+        $connection = ConnectionManager::get('test_shared_cache');
+        $this->assertSame([], $connection->getSchemaCollection()->listTables());
+
+        $connection->query('CREATE TABLE test (test int);');
+        $this->assertSame(['test'], $connection->getSchemaCollection()->listTables());
+
+        ConnectionManager::setConfig('test_shared_cache2', [
+            'className' => Connection::class,
+            'driver' => Sqlite::class,
+            'database' => ':memory:',
+            'cache' => 'shared',
+        ]);
+        $connection = ConnectionManager::get('test_shared_cache2');
+        $this->assertSame(['test'], $connection->getSchemaCollection()->listTables());
+        $this->assertFileDoesNotExist('file::memory:?cache=shared');
+    }
+
+    /**
      * Data provider for schemaValue()
      *
      * @return array