private void UpgradeDatabase(FileInfo path) { var oldFilename = path.FullName; var newFilename = Path.ChangeExtension(oldFilename, DatabaseSuffix); var newFile = new FileInfo(newFilename); if (!oldFilename.Equals(newFilename) && newFile.Exists) { var msg = String.Format("Cannot rename {0} to {1}, {2} already exists", oldFilename, newFilename, newFilename); Log.W(Database.TAG, msg); return; } var name = Path.GetFileNameWithoutExtension(Path.Combine(path.Directory.FullName, newFilename)); var db = GetDatabaseWithoutOpening(name, false); if (db == null) { Log.W(TAG, "Upgrade failed for {0} (Creating new DB failed)", path.Name); return; } db.Dispose(); var upgrader = DatabaseUpgraderFactory.CreateUpgrader(db, oldFilename); var status = upgrader.Import(); if (status.IsError) { Log.W(TAG, "Upgrade failed for {0} (Status {1})", path.Name, status); upgrader.Backout(); return; } Log.D(TAG, "...Success!"); }
public void TestUpgradeOldDatabaseFiles() { var testDirName = "test-directory-" + Runtime.CurrentTimeMillis(); var rootDirPath = RootDirectory.FullName; var testDirPath = Path.Combine(rootDirPath, testDirName); var testDirInfo = Directory.CreateDirectory(testDirPath); var dbStream = GetAsset("withattachments.cblite"); var destStream = File.OpenWrite(Path.Combine(testDirPath, "withattachments" + Manager.DatabaseSuffix)); dbStream.CopyTo(destStream); dbStream.Dispose(); destStream.Dispose(); var attStream = GetAsset("attachment.blob"); Directory.CreateDirectory(Path.Combine(testDirPath, "withattachments/attachments")); destStream = File.OpenWrite(Path.Combine(testDirPath, "withattachments/attachments/356a192b7913b04c54574d18c28d46e6395428ab.blob")); attStream.CopyTo(destStream); destStream.Dispose(); attStream.Dispose(); StopCBLite(); manager = new Manager(testDirInfo, Manager.DefaultOptions); var db = manager.GetDatabaseWithoutOpening("withattachments", true); int version = DatabaseUpgraderFactory.SchemaVersion(db.Path); Assert.IsTrue(version >= 101, "Upgrade failed"); Assert.IsFalse(Directory.Exists(Path.Combine(testDirPath, "withattachments/attachments")), "Failed to remove old attachments dir"); Assert.IsTrue(Directory.Exists(Path.Combine(testDirPath, "withattachments attachments")), "Failed to create new attachments dir"); }
private bool UpgradeDatabase(FileInfo path) { #if !NOSQLITE var previousStorageType = StorageType; try { StorageType = "SQLite"; var oldFilename = path.FullName; var newFilename = Path.ChangeExtension(oldFilename, DatabaseSuffix); var newFile = new DirectoryInfo(newFilename); if (!oldFilename.Equals(newFilename) && newFile.Exists) { var msg = String.Format("Cannot move {0} to {1}, {2} already exists", oldFilename, newFilename, newFilename); Log.W(Database.TAG, msg); return(false); } var name = Path.GetFileNameWithoutExtension(Path.Combine(path.DirectoryName, newFilename)); var db = GetDatabaseWithoutOpening(name, false); if (db == null) { Log.W(TAG, "Upgrade failed for {0} (Creating new DB failed)", path.Name); return(false); } db.Dispose(); var upgrader = DatabaseUpgraderFactory.CreateUpgrader(db, oldFilename); try { upgrader.Import(); } catch (CouchbaseLiteException e) { Log.W(TAG, "Upgrade failed for {0} (Status {1})", path.Name, e.CBLStatus); upgrader.Backout(); return(false); } Log.D(TAG, "...Success!"); return(true); } finally { StorageType = previousStorageType; } #endif }
public void Import() { // Rename the old database file for migration: var destPath = Path.ChangeExtension(_path, Manager.DatabaseSuffixv1 + "-mgr"); if (!MoveSqliteFiles(_path, destPath)) { MoveSqliteFiles(destPath, _path); throw Misc.CreateExceptionAndLog(Log.To.Upgrade, StatusCode.InternalServerError, TAG, "Upgrade failed: Cannot rename the old sqlite files"); } int version = DatabaseUpgraderFactory.SchemaVersion(destPath); if (version < 0) { throw Misc.CreateExceptionAndLog(Log.To.Upgrade, StatusCode.CorruptError, TAG, "Cannot determine database schema version"); } // Open source (SQLite) database: var err = raw.sqlite3_open_v2(destPath, out _sqlite, raw.SQLITE_OPEN_READWRITE, null); if (err > 0) { throw Misc.CreateExceptionAndLog(Log.To.Upgrade, SqliteErrToStatus(err).Code, TAG, "SQLite error while opening source database ({0})", err); } raw.sqlite3_create_collation(_sqlite, "JSON", raw.SQLITE_UTF8, CollateRevIDs); sqlite3_stmt stmt = null; PrepareSQL(ref stmt, "SELECT name FROM sqlite_master WHERE type='table' AND name='maps'"); err = raw.sqlite3_step(stmt); if (err == raw.SQLITE_ROW) { sqlite3_stmt stmt2 = null; PrepareSQL(ref stmt2, "SELECT * FROM maps"); while ((err = raw.sqlite3_step(stmt2)) == raw.SQLITE_ROW) { int viewId = raw.sqlite3_column_int(stmt2, 0); sqlite3_stmt stmt3 = null; PrepareSQL(ref stmt3, "CREATE TABLE IF NOT EXISTS maps_" + viewId + " (sequence INTEGER NOT NULL REFERENCES revs(sequence) ON DELETE CASCADE," + "key TEXT NOT NULL COLLATE JSON," + "value TEXT," + "fulltext_id INTEGER, " + "bbox_id INTEGER, " + "geokey BLOB)"); raw.sqlite3_step(stmt3); raw.sqlite3_finalize(stmt3); stmt3 = null; var sequence = raw.sqlite3_column_int64(stmt2, 1); var key = raw.sqlite3_column_text(stmt2, 2); var value = raw.sqlite3_column_text(stmt2, 3); var insertSql = String.Format("INSERT INTO maps_{0} (sequence, key, value) VALUES (?, ?, ?)", viewId); PrepareSQL(ref stmt3, insertSql); raw.sqlite3_bind_int64(stmt3, 0, sequence); raw.sqlite3_bind_text(stmt3, 1, key); raw.sqlite3_bind_text(stmt3, 2, value); raw.sqlite3_step(stmt3); raw.sqlite3_finalize(stmt3); } raw.sqlite3_finalize(stmt2); stmt2 = null; PrepareSQL(ref stmt2, "DROP TABLE maps"); raw.sqlite3_step(stmt2); raw.sqlite3_finalize(stmt2); } raw.sqlite3_finalize(stmt); raw.sqlite3_close(_sqlite); if (err != raw.SQLITE_DONE) { throw Misc.CreateExceptionAndLog(Log.To.Upgrade, SqliteErrToStatus(err).Code, TAG, "SQLite error during upgrade process ({0})", err); } if (version >= 101) { _db.Delete(); MoveSqliteFiles(destPath, _path); var secondaryUpgrade = new v11_upgrader(_db, _path); secondaryUpgrade.Import(); var newPath = Path.Combine(Path.GetDirectoryName(_path), _db.Name + Manager.DatabaseSuffix); if (newPath != _db.DbDirectory) { Directory.Move(Path.Combine(Path.GetDirectoryName(_path), _db.Name + Manager.DatabaseSuffix), _db.DbDirectory); } return; } Log.To.Upgrade.I(TAG, "Upgrading database v1.0 ({0}) to v1.1 at {1} ...", version, _path); err = raw.sqlite3_open_v2(destPath, out _sqlite, raw.SQLITE_OPEN_READONLY, null); if (err > 0) { throw Misc.CreateExceptionAndLog(Log.To.Upgrade, SqliteErrToStatus(err).Code, TAG, "Error opening destination SQLite file ({0})", err); } raw.sqlite3_create_collation(_sqlite, "REVID", raw.SQLITE_UTF8, CollateRevIDs); // Open destination database: try { _db.Open(); } catch (CouchbaseLiteException) { Log.To.Upgrade.E(TAG, "Upgrade failed: Couldn't open new db, rethrowing..."); throw; } catch (Exception e) { throw Misc.CreateExceptionAndLog(Log.To.Upgrade, e, TAG, "Error during upgrade; couldn't open new db"); } try { MoveAttachmentsDir(); } catch (CouchbaseLiteException) { Log.To.Upgrade.E(TAG, "Failed to move attachments directory for database at '{0}', rethrowing...", _path); throw; } catch (Exception e) { throw Misc.CreateExceptionAndLog(Log.To.Upgrade, e, TAG, "Error moving attachments directory for database at '{0}'", _path); } // Upgrade documents: // CREATE TABLE docs (doc_id INTEGER PRIMARY KEY, docid TEXT UNIQUE NOT NULL); sqlite3_stmt docQuery = null; PrepareSQL(ref docQuery, "SELECT doc_id, docid FROM docs"); _db.RunInTransaction(() => { int transactionErr; int count = 0; while (raw.SQLITE_ROW == (transactionErr = raw.sqlite3_step(docQuery))) { long docNumericID = raw.sqlite3_column_int64(docQuery, 0); string docID = raw.sqlite3_column_text(docQuery, 1); try { ImportDoc(docID, docNumericID); } catch (CouchbaseLiteException) { Log.To.Upgrade.E(TAG, "Failed to import document #{0} ({1}), rethrowing", docNumericID, new SecureLogString(docID, LogMessageSensitivity.PotentiallyInsecure)); throw; } catch (Exception e) { throw Misc.CreateExceptionAndLog(Log.To.Upgrade, e, TAG, "Error importing documents"); } if ((++count % 1000) == 0) { Log.To.Upgrade.I(TAG, "Migrated {0} documents", count); } } return(transactionErr == raw.SQLITE_DONE); }); raw.sqlite3_finalize(docQuery); try { ImportLocalDocs(); } catch (CouchbaseLiteException) { Log.To.Upgrade.E(TAG, "Failed to import local docs for database '{0}', rethrowing...", _path); throw; } catch (Exception e) { throw Misc.CreateExceptionAndLog(Log.To.Upgrade, e, TAG, "Error importing local docs for database '{0}'", _path); } try { ImportInfo(); } catch (CouchbaseLiteException) { Log.To.Upgrade.E(TAG, "Failed to import info for database '{0}', rethrowing...", _path); throw; } catch (Exception e) { throw Misc.CreateExceptionAndLog(Log.To.Upgrade, e, TAG, "Error importing info for database '{0}'", _path); } raw.sqlite3_close(_sqlite); _sqlite = null; File.Delete(destPath); File.Delete(destPath + "-wal"); File.Delete(destPath + "-shm"); }