From a5987afeb92715a342d77c04a3f29808fa7f0c02 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Tue, 5 Jan 2016 16:28:59 +0200 Subject: [PATCH] [core] Added versioning to the cache database Force drop the table when the version doesn't match. Previously it was assumed (my bad) that CREATE TABLE IF NOT EXISTS would compare the table schema, which is not true. --- platform/default/sqlite_cache.cpp | 38 ++++++++++++++++++++++++-- platform/default/sqlite_cache_impl.hpp | 3 ++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/platform/default/sqlite_cache.cpp b/platform/default/sqlite_cache.cpp index 4d8cb8180..74aecc4e8 100644 --- a/platform/default/sqlite_cache.cpp +++ b/platform/default/sqlite_cache.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -63,6 +64,12 @@ void SQLiteCache::Impl::createDatabase() { db = std::make_unique(path.c_str(), ReadWrite | Create); } +int SQLiteCache::Impl::schemaVersion() const { + // WARNING: Bump the version when changing the cache + // scheme to force the table to be recreated. + return 1; +} + void SQLiteCache::Impl::createSchema() { constexpr const char *const sql = "" "CREATE TABLE IF NOT EXISTS `http_cache` (" @@ -77,10 +84,13 @@ void SQLiteCache::Impl::createSchema() { " `compressed` INTEGER NOT NULL DEFAULT 0" // Whether the data is compressed. ");" "CREATE INDEX IF NOT EXISTS `http_cache_kind_idx` ON `http_cache` (`kind`);" - "CREATE INDEX IF NOT EXISTS `http_cache_accessed_idx` ON `http_cache` (`modified`);"; + "CREATE INDEX IF NOT EXISTS `http_cache_accessed_idx` ON `http_cache` (`accessed`);"; + + ensureSchemaVersion(); try { db->exec(sql); + db->exec("PRAGMA user_version = " + util::toString(schemaVersion())); schema = true; } catch (mapbox::sqlite::Exception &ex) { if (ex.code == SQLITE_NOTADB) { @@ -97,9 +107,33 @@ void SQLiteCache::Impl::createSchema() { } // Creating the database table + index failed. That means there may already be one, likely - // with different columsn. Drop it and try to create a new one. + // with different columns. Drop it and try to create a new one. db->exec("DROP TABLE IF EXISTS `http_cache`"); db->exec(sql); + db->exec("PRAGMA user_version = " + util::toString(schemaVersion())); + } +} + +void SQLiteCache::Impl::ensureSchemaVersion() { + try { + Statement userVersionStmt(db->prepare("PRAGMA user_version")); + if (userVersionStmt.run() && userVersionStmt.get(0) == schemaVersion()) { + return; + } + } catch (mapbox::sqlite::Exception& ex) { + if (ex.code == SQLITE_NOTADB) { + return; + } + + Log::Error(Event::Database, ex.code, ex.what()); + } + + // Version mismatch, drop the table so it will + // get recreated by `createSchema()`. + try { + db->exec("DROP TABLE IF EXISTS `http_cache`"); + } catch (mapbox::sqlite::Exception& ex) { + Log::Error(Event::Database, ex.code, ex.what()); } } diff --git a/platform/default/sqlite_cache_impl.hpp b/platform/default/sqlite_cache_impl.hpp index be2db5df4..8ad22d79f 100644 --- a/platform/default/sqlite_cache_impl.hpp +++ b/platform/default/sqlite_cache_impl.hpp @@ -42,6 +42,9 @@ private: void createDatabase(); void createSchema(); + int schemaVersion() const; + void ensureSchemaVersion(); + int pageSize = 0; uint64_t maximumCacheSize;