summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--platform/default/mbgl/storage/offline_database.cpp116
-rw-r--r--platform/default/mbgl/storage/offline_database.hpp1
-rw-r--r--platform/default/sqlite3.hpp5
-rw-r--r--test/storage/offline_database.test.cpp25
-rw-r--r--test/storage/sqlite.test.cpp6
5 files changed, 69 insertions, 84 deletions
diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp
index 2c4ee2da31..24fc0f2335 100644
--- a/platform/default/mbgl/storage/offline_database.cpp
+++ b/platform/default/mbgl/storage/offline_database.cpp
@@ -28,67 +28,70 @@ OfflineDatabase::~OfflineDatabase() {
}
void OfflineDatabase::ensureSchema() {
- if (path != ":memory:") {
- auto result = mapbox::sqlite::Database::tryOpen(path, mapbox::sqlite::ReadWrite);
- if (result.is<mapbox::sqlite::Exception>()) {
- const auto& ex = result.get<mapbox::sqlite::Exception>();
- if (ex.code == mapbox::sqlite::ResultCode::NotADB) {
- // Corrupted; blow it away.
- removeExisting();
- } else if (ex.code == mapbox::sqlite::ResultCode::CantOpen) {
- // Doesn't exist yet.
- } else {
- Log::Error(Event::Database, "Unexpected error connecting to database: %s", ex.what());
- throw ex;
- }
+ auto result = mapbox::sqlite::Database::tryOpen(path, mapbox::sqlite::ReadWriteCreate);
+ if (result.is<mapbox::sqlite::Exception>()) {
+ const auto& ex = result.get<mapbox::sqlite::Exception>();
+ if (ex.code == mapbox::sqlite::ResultCode::NotADB) {
+ // Corrupted; blow it away.
+ removeExisting();
+ result = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadWriteCreate);
} else {
- try {
- db = std::make_unique<mapbox::sqlite::Database>(std::move(result.get<mapbox::sqlite::Database>()));
- db->setBusyTimeout(Milliseconds::max());
- db->exec("PRAGMA foreign_keys = ON");
-
- switch (userVersion()) {
- case 0:
- case 1:
- // cache-only database; ok to delete
- removeExisting();
- break;
- case 2:
- migrateToVersion3();
- // fall through
- case 3:
- case 4:
- migrateToVersion5();
- // fall through
- case 5:
- migrateToVersion6();
- // fall through
- case 6:
- // happy path; we're done
- return;
- default:
- // downgrade, delete the database
- removeExisting();
- break;
- }
- } catch (const mapbox::sqlite::Exception& ex) {
- // Unfortunately, SQLITE_NOTADB is not always reported upon opening the database.
- // Apparently sometimes it is delayed until the first read operation.
- if (ex.code == mapbox::sqlite::ResultCode::NotADB) {
- removeExisting();
- } else {
- throw;
- }
- }
+ Log::Error(Event::Database, "Unexpected error connecting to database: %s", ex.what());
+ throw ex;
}
}
try {
- #include "offline_schema.cpp.include"
-
- db = std::make_unique<mapbox::sqlite::Database>(mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadWrite | mapbox::sqlite::Create));
+ assert(result.is<mapbox::sqlite::Database>());
+ db = std::make_unique<mapbox::sqlite::Database>(std::move(result.get<mapbox::sqlite::Database>()));
db->setBusyTimeout(Milliseconds::max());
db->exec("PRAGMA foreign_keys = ON");
+
+ switch (userVersion()) {
+ case 0:
+ case 1:
+ // Newly created database, or old cache-only database; remove old table if it exists.
+ removeOldCacheTable();
+ break;
+ case 2:
+ migrateToVersion3();
+ // fall through
+ case 3:
+ case 4:
+ migrateToVersion5();
+ // fall through
+ case 5:
+ migrateToVersion6();
+ // fall through
+ case 6:
+ // happy path; we're done
+ return;
+ default:
+ // downgrade, delete the database
+ removeExisting();
+ break;
+ }
+ } catch (const mapbox::sqlite::Exception& ex) {
+ // Unfortunately, SQLITE_NOTADB is not always reported upon opening the database.
+ // Apparently sometimes it is delayed until the first read operation.
+ if (ex.code == mapbox::sqlite::ResultCode::NotADB) {
+ removeExisting();
+ } else {
+ throw;
+ }
+ }
+
+ try {
+ #include "offline_schema.cpp.include"
+
+ // When downgrading the database, or when the database is corrupt, we've deleted the old database handle,
+ // so we need to reopen it.
+ if (!db) {
+ db = std::make_unique<mapbox::sqlite::Database>(mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadWriteCreate));
+ db->setBusyTimeout(Milliseconds::max());
+ db->exec("PRAGMA foreign_keys = ON");
+ }
+
db->exec("PRAGMA auto_vacuum = INCREMENTAL");
db->exec("PRAGMA journal_mode = DELETE");
db->exec("PRAGMA synchronous = FULL");
@@ -117,6 +120,11 @@ void OfflineDatabase::removeExisting() {
}
}
+void OfflineDatabase::removeOldCacheTable() {
+ db->exec("DROP TABLE IF EXISTS http_cache");
+ db->exec("VACUUM");
+}
+
void OfflineDatabase::migrateToVersion3() {
db->exec("PRAGMA auto_vacuum = INCREMENTAL");
db->exec("VACUUM");
diff --git a/platform/default/mbgl/storage/offline_database.hpp b/platform/default/mbgl/storage/offline_database.hpp
index 639bd42e2d..38eb3783ba 100644
--- a/platform/default/mbgl/storage/offline_database.hpp
+++ b/platform/default/mbgl/storage/offline_database.hpp
@@ -70,6 +70,7 @@ private:
int userVersion();
void ensureSchema();
void removeExisting();
+ void removeOldCacheTable();
void migrateToVersion3();
void migrateToVersion5();
void migrateToVersion6();
diff --git a/platform/default/sqlite3.hpp b/platform/default/sqlite3.hpp
index 8686c55666..612e92acc6 100644
--- a/platform/default/sqlite3.hpp
+++ b/platform/default/sqlite3.hpp
@@ -11,9 +11,8 @@ namespace mapbox {
namespace sqlite {
enum OpenFlag : int {
- ReadOnly = 0x00000001,
- ReadWrite = 0x00000002,
- Create = 0x00000004,
+ ReadOnly = 0b001,
+ ReadWriteCreate = 0b110,
};
enum class ResultCode : int {
diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp
index e54cd6813b..36b71bc4b4 100644
--- a/test/storage/offline_database.test.cpp
+++ b/test/storage/offline_database.test.cpp
@@ -23,17 +23,6 @@ TEST(OfflineDatabase, TEST_REQUIRES_WRITE(Create)) {
OfflineDatabase db(filename);
EXPECT_FALSE(bool(db.get({ Resource::Unknown, "mapbox://test" })));
-#ifdef __QT__
- // Qt doesn't support opening a SQLite database without also creating it if it doesn't exist yet.
- // Therefore, we're currently using the code path that thinks that we opened an old database
- // (user_version = 0), deletes and recreates the database.
- EXPECT_EQ(1u, log.count({ EventSeverity::Warning, Event::Database, -1, "Removing existing incompatible offline database" }));
-#endif
-#ifndef __QT__
- // Only non-Qt platforms are setting a logger on the SQLite object.
- EXPECT_EQ(1u, log.count({ EventSeverity::Info, Event::Database, static_cast<int64_t>(mapbox::sqlite::ResultCode::CantOpen), "cannot open file" }, true));
- EXPECT_EQ(1u, log.count({ EventSeverity::Info, Event::Database, static_cast<int64_t>(mapbox::sqlite::ResultCode::CantOpen), "No such file or directory" }, true));
-#endif
EXPECT_EQ(0u, log.uncheckedCount());
}
@@ -42,13 +31,12 @@ TEST(OfflineDatabase, TEST_REQUIRES_WRITE(SchemaVersion)) {
util::deleteFile(filename);
{
- mapbox::sqlite::Database db = mapbox::sqlite::Database::open(filename, mapbox::sqlite::Create | mapbox::sqlite::ReadWrite);
+ mapbox::sqlite::Database db = mapbox::sqlite::Database::open(filename, mapbox::sqlite::ReadWriteCreate);
db.exec("PRAGMA user_version = 1");
}
OfflineDatabase db(filename);
- EXPECT_EQ(1u, log.count({ EventSeverity::Warning, Event::Database, -1, "Removing existing incompatible offline database" }));
EXPECT_EQ(0u, log.uncheckedCount());
}
@@ -339,17 +327,6 @@ TEST(OfflineDatabase, TEST_REQUIRES_WRITE(ConcurrentUse)) {
util::deleteFile(filename);
OfflineDatabase db1(filename);
-#ifdef __QT__
- // Qt doesn't support opening a SQLite database without also creating it if it doesn't exist yet.
- // Therefore, we're currently using the code path that thinks that we opened an old database
- // (user_version = 0), deletes and recreates the database.
- EXPECT_EQ(1u, log.count({ EventSeverity::Warning, Event::Database, -1, "Removing existing incompatible offline database" }));
-#endif
-#ifndef __QT__
- // Only non-Qt platforms are setting a logger on the SQLite object.
- EXPECT_EQ(1u, log.count({ EventSeverity::Info, Event::Database, static_cast<int64_t>(mapbox::sqlite::ResultCode::CantOpen), "cannot open file" }, true));
- EXPECT_EQ(1u, log.count({ EventSeverity::Info, Event::Database, static_cast<int64_t>(mapbox::sqlite::ResultCode::CantOpen), "No such file or directory" }, true));
-#endif
EXPECT_EQ(0u, log.uncheckedCount());
OfflineDatabase db2(filename);
diff --git a/test/storage/sqlite.test.cpp b/test/storage/sqlite.test.cpp
index a7c9d95e9b..22958c8bed 100644
--- a/test/storage/sqlite.test.cpp
+++ b/test/storage/sqlite.test.cpp
@@ -8,7 +8,7 @@ using namespace mbgl;
TEST(SQLite, Statement) {
using namespace mbgl;
- mapbox::sqlite::Database db = mapbox::sqlite::Database::open(":memory:", mapbox::sqlite::Create | mapbox::sqlite::ReadWrite);
+ mapbox::sqlite::Database db = mapbox::sqlite::Database::open(":memory:", mapbox::sqlite::ReadWriteCreate);
db.exec("CREATE TABLE test (id INTEGER);");
mapbox::sqlite::Statement stmt1{ db, "INSERT INTO test (id) VALUES (?1);" };
@@ -49,7 +49,7 @@ TEST(SQLite, TEST_REQUIRES_WRITE(TryOpen)) {
TEST(SQLite, CloseDatabaseWithPendingTransaction) {
auto db = std::make_unique<mapbox::sqlite::Database>(mapbox::sqlite::Database::open(
- ":memory:", mapbox::sqlite::ReadWrite | mapbox::sqlite::Create));
+ ":memory:", mapbox::sqlite::ReadWriteCreate));
mapbox::sqlite::Transaction transaction(*db);
transaction.commit();
}
@@ -58,7 +58,7 @@ TEST(SQLite, CloseMovedDatabaseWithPendingTransaction) {
// Verifies that we can correctly commit a transaction even if we move the Database object to
// another address.
auto db1 = mapbox::sqlite::Database::open(":memory:",
- mapbox::sqlite::ReadWrite | mapbox::sqlite::Create);
+ mapbox::sqlite::ReadWriteCreate);
std::unique_ptr<mapbox::sqlite::Database> db2;
mapbox::sqlite::Transaction transaction(db1);
db2 = std::make_unique<mapbox::sqlite::Database>(std::move(db1));