mirror of
https://github.com/tnodir/fort
synced 2024-11-15 01:15:29 +00:00
UI: ConfManager: Import DB without app restarting
This commit is contained in:
parent
1e251de80b
commit
83114e1569
59
src/ui/3rdparty/sqlite/sqlitedb.cpp
vendored
59
src/ui/3rdparty/sqlite/sqlitedb.cpp
vendored
@ -88,6 +88,8 @@ bool SqliteDb::open()
|
||||
const bool ok = sqlite3_open_v2(filePathUtf8.data(), &m_db, m_openFlags, nullptr) == SQLITE_OK;
|
||||
|
||||
if (ok) {
|
||||
setBusyTimeoutMs(DATABASE_BUSY_TIMEOUT);
|
||||
|
||||
SqliteDbExt::registerExtensions(this);
|
||||
}
|
||||
|
||||
@ -300,10 +302,22 @@ QStringList SqliteDb::columnNames(const QString &tableName, const QString &schem
|
||||
return list;
|
||||
}
|
||||
|
||||
bool SqliteDb::import(SqliteDb::MigrateOptions &opt)
|
||||
{
|
||||
// Get the importing DB version
|
||||
{
|
||||
SqliteDb db(opt.backupFilePath, SqliteDb::OpenDefaultReadOnly);
|
||||
if (!db.open())
|
||||
return false;
|
||||
|
||||
opt.userVersion = db.userVersion();
|
||||
}
|
||||
|
||||
return importDb(opt);
|
||||
}
|
||||
|
||||
bool SqliteDb::migrate(MigrateOptions &opt)
|
||||
{
|
||||
setBusyTimeoutMs(DATABASE_BUSY_TIMEOUT);
|
||||
|
||||
if (!opt.sqlPragmas) {
|
||||
opt.sqlPragmas = defaultSqlPragmas;
|
||||
}
|
||||
@ -316,16 +330,14 @@ bool SqliteDb::migrate(MigrateOptions &opt)
|
||||
|
||||
opt.userVersion = userVersion;
|
||||
|
||||
// Check migration options
|
||||
if (!canMigrate(opt))
|
||||
return false;
|
||||
|
||||
// Migrate the DB
|
||||
const bool isNewDb = (userVersion == 0);
|
||||
if (isNewDb) {
|
||||
opt.recreate = false;
|
||||
}
|
||||
|
||||
opt.backupFilePath = backupFilePath();
|
||||
|
||||
return migrateDb(opt, userVersion, isNewDb);
|
||||
}
|
||||
|
||||
@ -347,6 +359,10 @@ bool SqliteDb::canMigrate(const MigrateOptions &opt) const
|
||||
|
||||
bool SqliteDb::migrateDb(const MigrateOptions &opt, int userVersion, bool isNewDb)
|
||||
{
|
||||
// Check migration options
|
||||
if (!canMigrate(opt))
|
||||
return false;
|
||||
|
||||
if (!migrateDbBegin(opt, userVersion, isNewDb))
|
||||
return false;
|
||||
|
||||
@ -422,7 +438,7 @@ bool SqliteDb::migrateDbBegin(const MigrateOptions &opt, int &userVersion, bool
|
||||
userVersion = 0;
|
||||
isNewDb = true;
|
||||
|
||||
return clearWithBackup(opt.sqlPragmas);
|
||||
return clearWithBackup(opt);
|
||||
}
|
||||
|
||||
bool SqliteDb::migrateDbEnd(const MigrateOptions &opt)
|
||||
@ -506,21 +522,19 @@ bool SqliteDb::createFtsTable(const FtsTable &ftsTable)
|
||||
return executeStr(sql);
|
||||
}
|
||||
|
||||
bool SqliteDb::clearWithBackup(const char *sqlPragmas)
|
||||
bool SqliteDb::clearWithBackup(const MigrateOptions &opt)
|
||||
{
|
||||
const QString oldEncoding = this->encoding();
|
||||
|
||||
close();
|
||||
|
||||
const QString tempFilePath = backupFilePath();
|
||||
|
||||
if (!(renameDbFile(m_filePath, tempFilePath) && open())) {
|
||||
if (!(renameDbFile(m_filePath, opt.backupFilePath) && open())) {
|
||||
qCWarning(LC) << "Cannot re-create the DB" << m_filePath;
|
||||
renameDbFile(tempFilePath, m_filePath);
|
||||
renameDbFile(opt.backupFilePath, m_filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
execute(sqlPragmas);
|
||||
execute(opt.sqlPragmas);
|
||||
setEncoding(oldEncoding);
|
||||
|
||||
return true;
|
||||
@ -530,16 +544,14 @@ bool SqliteDb::importBackup(const MigrateOptions &opt)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
const QString tempFilePath = backupFilePath();
|
||||
|
||||
// Re-import the DB
|
||||
if (opt.importOldData) {
|
||||
success = importDb(opt, tempFilePath);
|
||||
success = importDb(opt);
|
||||
}
|
||||
|
||||
// Remove the old DB
|
||||
if (success) {
|
||||
removeDbFile(tempFilePath);
|
||||
removeDbFile(opt.backupFilePath);
|
||||
}
|
||||
|
||||
return success;
|
||||
@ -550,11 +562,13 @@ QString SqliteDb::backupFilePath() const
|
||||
return m_filePath + ".temp";
|
||||
}
|
||||
|
||||
bool SqliteDb::importDb(const MigrateOptions &opt, const QString &sourceFilePath)
|
||||
bool SqliteDb::importDb(const MigrateOptions &opt)
|
||||
{
|
||||
const QString srcSchema = migrationOldSchemaName();
|
||||
const QString dstSchema = migrationNewSchemaName();
|
||||
|
||||
const QString &sourceFilePath = opt.backupFilePath;
|
||||
|
||||
if (!attach(srcSchema, sourceFilePath)) {
|
||||
qCWarning(LC) << "Cannot attach the DB" << sourceFilePath << "Error:" << errorMessage();
|
||||
return false;
|
||||
@ -587,6 +601,8 @@ bool SqliteDb::copyTables(const QString &srcSchema, const QString &dstSchema)
|
||||
const QStringList srcTableNames = tableNames(srcSchema);
|
||||
|
||||
for (const QString &tableName : srcTableNames) {
|
||||
clearTable(dstSchema, tableName);
|
||||
|
||||
if (!copyTable(srcSchema, dstSchema, tableName))
|
||||
return false;
|
||||
}
|
||||
@ -623,6 +639,13 @@ bool SqliteDb::copyTable(
|
||||
return executeStr(sql);
|
||||
}
|
||||
|
||||
bool SqliteDb::clearTable(const QString &dstSchema, const QString &tableName)
|
||||
{
|
||||
const auto sql = QString("DELETE FROM %1;").arg(entityName(dstSchema, tableName));
|
||||
|
||||
return executeStr(sql);
|
||||
}
|
||||
|
||||
SqliteStmt *SqliteDb::stmt(const char *sql)
|
||||
{
|
||||
SqliteStmt *stmt = m_stmts.value(sql);
|
||||
|
15
src/ui/3rdparty/sqlite/sqlitedb.h
vendored
15
src/ui/3rdparty/sqlite/sqlitedb.h
vendored
@ -45,15 +45,21 @@ public:
|
||||
|
||||
struct MigrateOptions
|
||||
{
|
||||
const QString sqlDir;
|
||||
const char *sqlDir;
|
||||
const char *sqlPragmas = nullptr;
|
||||
|
||||
int version = 0;
|
||||
int userVersion = 0;
|
||||
|
||||
bool recreate = true;
|
||||
bool importOldData = true;
|
||||
bool autoCopyTables = true;
|
||||
|
||||
QString backupFilePath;
|
||||
|
||||
SQLITEDB_MIGRATE_FUNC migrateFunc = nullptr;
|
||||
void *migrateContext = nullptr;
|
||||
|
||||
QVector<FtsTable> ftsTables;
|
||||
};
|
||||
|
||||
@ -115,6 +121,8 @@ public:
|
||||
QStringList tableNames(const QString &schemaName = {});
|
||||
QStringList columnNames(const QString &tableName, const QString &schemaName = {});
|
||||
|
||||
bool import(SqliteDb::MigrateOptions &opt);
|
||||
|
||||
bool migrate(SqliteDb::MigrateOptions &opt);
|
||||
|
||||
SqliteStmt *stmt(const char *sql);
|
||||
@ -136,14 +144,15 @@ private:
|
||||
bool createFtsTables(const MigrateOptions &opt);
|
||||
bool createFtsTable(const FtsTable &ftsTable);
|
||||
|
||||
bool clearWithBackup(const char *sqlPragmas);
|
||||
bool clearWithBackup(const MigrateOptions &opt);
|
||||
bool importBackup(const MigrateOptions &opt);
|
||||
|
||||
QString backupFilePath() const;
|
||||
|
||||
bool importDb(const MigrateOptions &opt, const QString &sourceFilePath);
|
||||
bool importDb(const MigrateOptions &opt);
|
||||
bool copyTables(const QString &srcSchema, const QString &dstSchema);
|
||||
bool copyTable(const QString &srcSchema, const QString &dstSchema, const QString &tableName);
|
||||
bool clearTable(const QString &dstSchema, const QString &tableName);
|
||||
|
||||
void clearStmts();
|
||||
|
||||
|
@ -219,6 +219,30 @@ bool migrateFunc(SqliteDb *db, int version, bool isNewDb, void *ctx)
|
||||
return true;
|
||||
}
|
||||
|
||||
SqliteDb::MigrateOptions migrateOptions()
|
||||
{
|
||||
SqliteDb::MigrateOptions opt = {
|
||||
.sqlDir = ":/conf/migrations",
|
||||
.version = DATABASE_USER_VERSION,
|
||||
.recreate = true,
|
||||
.migrateFunc = &migrateFunc,
|
||||
.ftsTables = {
|
||||
{
|
||||
.contentTable = "app",
|
||||
.contentRowid = "app_id",
|
||||
.columns = { "path", "name", "notes" }
|
||||
},
|
||||
{
|
||||
.contentTable = "rule",
|
||||
.contentRowid = "rule_id",
|
||||
.columns = { "name", "notes" }
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return opt;
|
||||
}
|
||||
|
||||
bool loadAddressGroups(SqliteDb *db, const QList<AddressGroup *> &addressGroups, int &index)
|
||||
{
|
||||
SqliteStmt stmt;
|
||||
@ -512,24 +536,7 @@ bool ConfManager::setupDb()
|
||||
return false;
|
||||
}
|
||||
|
||||
SqliteDb::MigrateOptions opt = {
|
||||
.sqlDir = ":/conf/migrations",
|
||||
.version = DATABASE_USER_VERSION,
|
||||
.recreate = true,
|
||||
.migrateFunc = &migrateFunc,
|
||||
.ftsTables = {
|
||||
{
|
||||
.contentTable = "app",
|
||||
.contentRowid = "app_id",
|
||||
.columns = { "path", "name", "notes" }
|
||||
},
|
||||
{
|
||||
.contentTable = "rule",
|
||||
.contentRowid = "rule_id",
|
||||
.columns = { "name", "notes" }
|
||||
},
|
||||
},
|
||||
};
|
||||
SqliteDb::MigrateOptions opt = migrateOptions();
|
||||
|
||||
if (!sqliteDb()->migrate(opt)) {
|
||||
qCCritical(LC) << "Migration error" << sqliteDb()->filePath();
|
||||
@ -773,13 +780,11 @@ bool ConfManager::importBackup(const QString &path)
|
||||
return false;
|
||||
|
||||
settings->clearCache();
|
||||
|
||||
emit iniUserChanged(iniUser(), /*onlyFlags=*/false);
|
||||
}
|
||||
|
||||
// Import DB: Close DB from UI side
|
||||
{
|
||||
sqliteDb()->close();
|
||||
}
|
||||
|
||||
// Import DB
|
||||
return importMasterBackup(inPath);
|
||||
}
|
||||
|
||||
@ -798,17 +803,20 @@ bool ConfManager::importMasterBackup(const QString &path)
|
||||
|
||||
// Import Db
|
||||
if (ok) {
|
||||
sqliteDb()->close();
|
||||
SqliteDb::MigrateOptions opt = migrateOptions();
|
||||
|
||||
ok = importFile(sqliteDb()->filePath(), path);
|
||||
opt.backupFilePath = path + FileUtil::fileName(sqliteDb()->filePath());
|
||||
|
||||
ok = sqliteDb()->import(opt);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
if (ok) {
|
||||
emit iniChanged(conf()->ini());
|
||||
emit confChanged(/*onlyFlags=*/false);
|
||||
} else {
|
||||
qCWarning(LC) << "Import error:" << path;
|
||||
}
|
||||
|
||||
IoC<FortManager>()->processRestartRequired("Backup Imported");
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user