fix wrong stuff when doing backup of DB - was not working because of WAL journalling mode
This commit is contained in:
parent
96920ab723
commit
2deb6446eb
@ -5,12 +5,6 @@
|
|||||||
#include "exceptions/applicationexception.h"
|
#include "exceptions/applicationexception.h"
|
||||||
#include "miscellaneous/application.h"
|
#include "miscellaneous/application.h"
|
||||||
|
|
||||||
#if defined(SYSTEM_SQLITE3)
|
|
||||||
#include <sqlite3.h>
|
|
||||||
#else
|
|
||||||
#include "3rd-party/sqlite/sqlite3.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QSqlDriver>
|
#include <QSqlDriver>
|
||||||
#include <QSqlError>
|
#include <QSqlError>
|
||||||
@ -44,25 +38,25 @@ QString SqliteDriver::ddlFilePrefix() const {
|
|||||||
return QSL("sqlite");
|
return QSL("sqlite");
|
||||||
}
|
}
|
||||||
|
|
||||||
int loadOrSaveDb(sqlite3* pInMemory, const char* zFilename, int isSave) {
|
int SqliteDriver::loadOrSaveDbInMemoryDb(sqlite3* in_memory_db, const char* db_filename, bool save) {
|
||||||
int rc; /* Function return code */
|
int rc; /* Function return code */
|
||||||
sqlite3* pFile; /* Database connection opened on zFilename */
|
sqlite3* p_file; /* Database connection opened on zFilename */
|
||||||
sqlite3_backup* pBackup; /* Backup object used to copy data */
|
sqlite3_backup* p_backup; /* Backup object used to copy data */
|
||||||
sqlite3* pTo; /* Database to copy to (pFile or pInMemory) */
|
sqlite3* p_to; /* Database to copy to (pFile or pInMemory) */
|
||||||
sqlite3* pFrom; /* Database to copy from (pFile or pInMemory) */
|
sqlite3* p_from; /* Database to copy from (pFile or pInMemory) */
|
||||||
|
|
||||||
/* Open the database file identified by zFilename. Exit early if this fails
|
/* Open the database file identified by zFilename. Exit early if this fails
|
||||||
** for any reason. */
|
** for any reason. */
|
||||||
rc = sqlite3_open(zFilename, &pFile);
|
rc = sqlite3_open(db_filename, &p_file);
|
||||||
if (rc == SQLITE_OK) {
|
|
||||||
|
|
||||||
|
if (rc == SQLITE_OK) {
|
||||||
/* If this is a 'load' operation (isSave==0), then data is copied
|
/* If this is a 'load' operation (isSave==0), then data is copied
|
||||||
** from the database file just opened to database pInMemory.
|
** from the database file just opened to database pInMemory.
|
||||||
** Otherwise, if this is a 'save' operation (isSave==1), then data
|
** Otherwise, if this is a 'save' operation (isSave==1), then data
|
||||||
** is copied from pInMemory to pFile. Set the variables pFrom and
|
** is copied from pInMemory to pFile. Set the variables pFrom and
|
||||||
** pTo accordingly. */
|
** pTo accordingly. */
|
||||||
pFrom = (isSave ? pInMemory : pFile);
|
p_from = (save ? in_memory_db : p_file);
|
||||||
pTo = (isSave ? pFile : pInMemory);
|
p_to = (save ? p_file : in_memory_db);
|
||||||
|
|
||||||
/* Set up the backup procedure to copy from the "main" database of
|
/* Set up the backup procedure to copy from the "main" database of
|
||||||
** connection pFile to the main database of connection pInMemory.
|
** connection pFile to the main database of connection pInMemory.
|
||||||
@ -76,19 +70,19 @@ int loadOrSaveDb(sqlite3* pInMemory, const char* zFilename, int isSave) {
|
|||||||
** connection pTo. If no error occurred, then the error code belonging
|
** connection pTo. If no error occurred, then the error code belonging
|
||||||
** to pTo is set to SQLITE_OK.
|
** to pTo is set to SQLITE_OK.
|
||||||
*/
|
*/
|
||||||
pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
|
p_backup = sqlite3_backup_init(p_to, "main", p_from, "main");
|
||||||
if (pBackup) {
|
if (p_backup) {
|
||||||
(void)sqlite3_backup_step(pBackup, -1);
|
(void)sqlite3_backup_step(p_backup, -1);
|
||||||
(void)sqlite3_backup_finish(pBackup);
|
(void)sqlite3_backup_finish(p_backup);
|
||||||
}
|
}
|
||||||
rc = sqlite3_errcode(pTo);
|
rc = sqlite3_errcode(p_to);
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_db_cacheflush(pFile);
|
sqlite3_db_cacheflush(p_file);
|
||||||
|
|
||||||
/* Close the database connection opened on database file zFilename
|
/* Close the database connection opened on database file zFilename
|
||||||
** and return the result of this function. */
|
** and return the result of this function. */
|
||||||
(void)sqlite3_close(pFile);
|
(void)sqlite3_close(p_file);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,69 +90,28 @@ bool SqliteDriver::saveDatabase() {
|
|||||||
if (!m_inMemoryDatabase) {
|
if (!m_inMemoryDatabase) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
qDebugNN << LOGSEC_DB << "Saving in-memory working database back to persistent file-based storage.";
|
||||||
|
|
||||||
qDebugNN << LOGSEC_DB << "Saving in-memory working database back to persistent file-based storage.";
|
QSqlDatabase database = connection(QSL("SaveFromMemory"), DatabaseDriver::DesiredStorageType::StrictlyInMemory);
|
||||||
|
const QDir db_path(m_databaseFilePath);
|
||||||
|
QFile db_file(db_path.absoluteFilePath(QSL(APP_DB_SQLITE_FILE)));
|
||||||
|
QVariant v = database.driver()->handle();
|
||||||
|
|
||||||
QSqlDatabase database = connection(QSL("SaveFromMemory"), DatabaseDriver::DesiredStorageType::StrictlyInMemory);
|
if (v.isValid() && (qstrcmp(v.typeName(), "sqlite3*") == 0)) {
|
||||||
const QDir db_path(m_databaseFilePath);
|
// v.data() returns a pointer to the handle
|
||||||
QFile db_file(db_path.absoluteFilePath(QSL(APP_DB_SQLITE_FILE)));
|
sqlite3* handle = *static_cast<sqlite3**>(v.data());
|
||||||
QVariant v = database.driver()->handle();
|
|
||||||
|
|
||||||
if (v.isValid() && (qstrcmp(v.typeName(), "sqlite3*") == 0)) {
|
if (handle != nullptr) {
|
||||||
// v.data() returns a pointer to the handle
|
loadOrSaveDbInMemoryDb(handle, QDir::toNativeSeparators(db_file.fileName()).toStdString().c_str(), 1);
|
||||||
sqlite3* handle = *static_cast<sqlite3**>(v.data());
|
}
|
||||||
if (handle) {
|
else {
|
||||||
loadOrSaveDb(handle, QDir::toNativeSeparators(db_file.fileName()).toStdString().c_str(), 1);
|
throw ApplicationException(tr("cannot get native 'sqlite3' DB handle"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
/*
|
|
||||||
QSqlQuery copy_contents(database);
|
|
||||||
|
|
||||||
// Attach database.
|
|
||||||
copy_contents.exec(QString(QSL("ATTACH DATABASE '%1' AS 'storage';")).arg(file_database.databaseName()));
|
|
||||||
|
|
||||||
// Copy all stuff.
|
|
||||||
QStringList tables;
|
|
||||||
|
|
||||||
if (copy_contents.exec(QSL("SELECT name FROM storage.sqlite_master WHERE type='table';"))) {
|
|
||||||
while (copy_contents.next()) {
|
|
||||||
tables.append(copy_contents.value(0).toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
qFatal("Cannot obtain list of table names from file-base SQLite database.");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const QString& table : tables) {
|
|
||||||
if (copy_contents.exec(QString(QSL("DELETE FROM storage.%1;")).arg(table))) {
|
|
||||||
qDebugNN << LOGSEC_DB << "Cleaning old data from 'storage." << table << "'.";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
qCriticalNN << LOGSEC_DB << "Failed to clean old data from 'storage." << table << "', error: '"
|
|
||||||
<< copy_contents.lastError().text() << "'.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy_contents.exec(QString(QSL("INSERT INTO storage.%1 SELECT * FROM main.%1;")).arg(table))) {
|
|
||||||
qDebugNN << LOGSEC_DB << "Copying new data from 'main." << table << "'.";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
qCriticalNN << LOGSEC_DB << "Failed to copy new data from 'main." << table << "', error: '"
|
|
||||||
<< copy_contents.lastError().text() << "'.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detach database and finish.
|
|
||||||
if (copy_contents.exec(QSL("DETACH 'storage'"))) {
|
|
||||||
qDebugNN << LOGSEC_DB << "Detaching persistent SQLite file.";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
qCriticalNN << LOGSEC_DB << "Failed to detach SQLite file, error: '" << copy_contents.lastError().text() << "'.";
|
|
||||||
}
|
|
||||||
|
|
||||||
copy_contents.finish();
|
|
||||||
return true;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QSqlDatabase SqliteDriver::connection(const QString& connection_name, DesiredStorageType desired_type) {
|
QSqlDatabase SqliteDriver::connection(const QString& connection_name, DesiredStorageType desired_type) {
|
||||||
@ -394,13 +347,13 @@ QString SqliteDriver::databaseFilePath() const {
|
|||||||
|
|
||||||
void SqliteDriver::setPragmas(QSqlQuery& query) {
|
void SqliteDriver::setPragmas(QSqlQuery& query) {
|
||||||
query.exec(QSL("PRAGMA encoding = \"UTF-8\""));
|
query.exec(QSL("PRAGMA encoding = \"UTF-8\""));
|
||||||
query.exec(QSL("PRAGMA synchronous = OFF"));
|
query.exec(QSL("PRAGMA page_size = 32768"));
|
||||||
// query.exec(QSL("PRAGMA journal_mode = MEMORY"));
|
query.exec(QSL("PRAGMA cache_size = 32768"));
|
||||||
query.exec(QSL("PRAGMA page_size = 4096"));
|
query.exec(QSL("PRAGMA mmap_size = 100000000"));
|
||||||
query.exec(QSL("PRAGMA cache_size = 16384"));
|
|
||||||
query.exec(QSL("PRAGMA count_changes = OFF"));
|
query.exec(QSL("PRAGMA count_changes = OFF"));
|
||||||
query.exec(QSL("PRAGMA temp_store = MEMORY"));
|
query.exec(QSL("PRAGMA temp_store = MEMORY"));
|
||||||
query.exec(QSL("PRAGMA journal_mode = WAL"));
|
query.exec(QSL("PRAGMA synchronous = OFF"));
|
||||||
|
query.exec(QSL("PRAGMA journal_mode = MEMORY"));
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 SqliteDriver::databaseDataSize() {
|
qint64 SqliteDriver::databaseDataSize() {
|
||||||
@ -436,6 +389,8 @@ QString SqliteDriver::qtDriverCode() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SqliteDriver::backupDatabase(const QString& backup_folder, const QString& backup_name) {
|
void SqliteDriver::backupDatabase(const QString& backup_folder, const QString& backup_name) {
|
||||||
|
qDebugNN << LOGSEC_DB << "Creating SQLite DB backup.";
|
||||||
|
|
||||||
saveDatabase();
|
saveDatabase();
|
||||||
|
|
||||||
if (!IOFactory::copyFile(databaseFilePath(),
|
if (!IOFactory::copyFile(databaseFilePath(),
|
||||||
|
@ -5,8 +5,14 @@
|
|||||||
|
|
||||||
#include "database/databasedriver.h"
|
#include "database/databasedriver.h"
|
||||||
|
|
||||||
|
#if defined(SYSTEM_SQLITE3)
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#else
|
||||||
|
#include "3rd-party/sqlite/sqlite3.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
class SqliteDriver : public DatabaseDriver {
|
class SqliteDriver : public DatabaseDriver {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SqliteDriver(bool in_memory, QObject* parent = nullptr);
|
explicit SqliteDriver(bool in_memory, QObject* parent = nullptr);
|
||||||
@ -19,7 +25,8 @@ class SqliteDriver : public DatabaseDriver {
|
|||||||
virtual bool initiateRestoration(const QString& database_package_file);
|
virtual bool initiateRestoration(const QString& database_package_file);
|
||||||
virtual bool finishRestoration();
|
virtual bool finishRestoration();
|
||||||
virtual QSqlDatabase connection(const QString& connection_name,
|
virtual QSqlDatabase connection(const QString& connection_name,
|
||||||
DatabaseDriver::DesiredStorageType desired_type = DatabaseDriver::DesiredStorageType::FromSettings);
|
DatabaseDriver::DesiredStorageType desired_type =
|
||||||
|
DatabaseDriver::DesiredStorageType::FromSettings);
|
||||||
virtual qint64 databaseDataSize();
|
virtual qint64 databaseDataSize();
|
||||||
virtual QString humanDriverType() const;
|
virtual QString humanDriverType() const;
|
||||||
virtual QString qtDriverCode() const;
|
virtual QString qtDriverCode() const;
|
||||||
@ -32,6 +39,9 @@ class SqliteDriver : public DatabaseDriver {
|
|||||||
void setPragmas(QSqlQuery& query);
|
void setPragmas(QSqlQuery& query);
|
||||||
QString databaseFilePath() const;
|
QString databaseFilePath() const;
|
||||||
|
|
||||||
|
// Uses native "sqlite3" handle to save or load in-memory DB from/to file.
|
||||||
|
int loadOrSaveDbInMemoryDb(sqlite3* in_memory_db, const char* db_filename, bool save);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_inMemoryDatabase;
|
bool m_inMemoryDatabase;
|
||||||
QString m_databaseFilePath;
|
QString m_databaseFilePath;
|
||||||
|
@ -790,7 +790,13 @@ void Application::onAboutToQuit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
qApp->feedReader()->quit();
|
qApp->feedReader()->quit();
|
||||||
database()->driver()->saveDatabase();
|
|
||||||
|
try {
|
||||||
|
database()->driver()->saveDatabase();
|
||||||
|
}
|
||||||
|
catch (const ApplicationException& ex) {
|
||||||
|
qCriticalNN << LOGSEC_DB << "Error when saving DB:" << QUOTE_W_SPACE_DOT(ex.message());
|
||||||
|
}
|
||||||
|
|
||||||
if (mainForm() != nullptr) {
|
if (mainForm() != nullptr) {
|
||||||
mainForm()->saveSize();
|
mainForm()->saveSize();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user