Work on bug/enhancement #95: rolling DB schema update.
This commit is contained in:
parent
504950f631
commit
a1e415c518
@ -68,7 +68,7 @@ CREATE TABLE IF NOT EXISTS Messages (
|
||||
author TEXT NOT NULL,
|
||||
date_created BIGINT NOT NULL CHECK (date_created != 0),
|
||||
contents TEXT,
|
||||
is_hidden INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_hidden >= 0 AND is_hidden <= 1),
|
||||
is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1),
|
||||
|
||||
FOREIGN KEY (feed) REFERENCES Feeds (id)
|
||||
);
|
||||
|
@ -62,7 +62,7 @@ CREATE TABLE IF NOT EXISTS Messages (
|
||||
author TEXT NOT NULL,
|
||||
date_created INTEGER NOT NULL CHECK (date_created != 0),
|
||||
contents TEXT,
|
||||
is_hidden INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_hidden >= 0 AND is_hidden <= 1),
|
||||
is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1),
|
||||
|
||||
FOREIGN KEY (feed) REFERENCES Feeds (id)
|
||||
);
|
||||
|
@ -62,7 +62,7 @@ CREATE TABLE IF NOT EXISTS Messages (
|
||||
author TEXT NOT NULL,
|
||||
date_created INTEGER NOT NULL CHECK (date_created != 0),
|
||||
contents TEXT,
|
||||
is_hidden INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_hidden >= 0 AND is_hidden <= 1),
|
||||
is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1),
|
||||
|
||||
FOREIGN KEY (feed) REFERENCES Feeds (id)
|
||||
);
|
@ -1,2 +0,0 @@
|
||||
ALTER TABLE Messages
|
||||
ADD COLUMN is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1);
|
4
resources/misc/db_update_mysql_1_2.sql
Normal file
4
resources/misc/db_update_mysql_1_2.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE Messages
|
||||
ADD COLUMN is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1);
|
||||
-- !
|
||||
UPDATE Information SET inf_value = '2' WHERE inf_key = 'schema_version';
|
@ -1,2 +0,0 @@
|
||||
ALTER TABLE Messages
|
||||
ADD COLUMN is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1);
|
4
resources/misc/db_update_sqlite_1_2.sql
Normal file
4
resources/misc/db_update_sqlite_1_2.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE Messages
|
||||
ADD COLUMN is_pdeleted INTEGER(1) NOT NULL DEFAULT 0 CHECK (is_pdeleted >= 0 AND is_pdeleted <= 1);
|
||||
-- !
|
||||
UPDATE Information SET inf_value = '2' WHERE inf_key = 'schema_version';
|
@ -4,6 +4,7 @@
|
||||
Fixed:
|
||||
<ul>
|
||||
<li>Database is now correctly restored when using SQLite memory databases.</li>
|
||||
<li>When items are deleted from recycle bin then they are kept in DB and marked as "permanently deleted" (bug # 95).'
|
||||
</ul>
|
||||
|
||||
Added:
|
||||
|
@ -120,7 +120,7 @@ bool FeedsModelRecycleBin::empty() {
|
||||
QSqlQuery query_empty_bin(db_handle);
|
||||
query_empty_bin.setForwardOnly(true);
|
||||
|
||||
if (!query_empty_bin.exec("DELETE FROM Messages WHERE is_deleted = 1;")) {
|
||||
if (!query_empty_bin.exec("UPDATE Messages SET is_pdeleted = 1 WHERE is_deleted = 1;")) {
|
||||
qWarning("Query execution failed for recycle bin emptying.");
|
||||
|
||||
db_handle.rollback();
|
||||
@ -148,7 +148,7 @@ bool FeedsModelRecycleBin::restore() {
|
||||
QSqlQuery query_empty_bin(db_handle);
|
||||
query_empty_bin.setForwardOnly(true);
|
||||
|
||||
if (!query_empty_bin.exec("UPDATE Messages SET is_deleted = 0 WHERE is_deleted = 1;")) {
|
||||
if (!query_empty_bin.exec("UPDATE Messages SET is_deleted = 0 WHERE is_deleted = 1 AND is_pdeleted = 0;")) {
|
||||
qWarning("Query execution failed for recycle bin restoring.");
|
||||
|
||||
db_handle.rollback();
|
||||
@ -170,7 +170,7 @@ void FeedsModelRecycleBin::updateCounts(bool update_total_count) {
|
||||
QSqlQuery query_all(database);
|
||||
query_all.setForwardOnly(true);
|
||||
|
||||
if (query_all.exec("SELECT count(*) FROM Messages WHERE is_read = 0 AND is_deleted = 1;") && query_all.next()) {
|
||||
if (query_all.exec("SELECT count(*) FROM Messages WHERE is_read = 0 AND is_deleted = 1 AND is_pdeleted = 0;") && query_all.next()) {
|
||||
m_unreadCount = query_all.value(0).toInt();
|
||||
}
|
||||
else {
|
||||
@ -178,7 +178,7 @@ void FeedsModelRecycleBin::updateCounts(bool update_total_count) {
|
||||
}
|
||||
|
||||
if (update_total_count) {
|
||||
if (query_all.exec("SELECT count(*) FROM Messages WHERE is_deleted = 1;") && query_all.next()) {
|
||||
if (query_all.exec("SELECT count(*) FROM Messages WHERE is_deleted = 1 AND is_pdeleted = 0;") && query_all.next()) {
|
||||
m_totalCount = query_all.value(0).toInt();
|
||||
}
|
||||
else {
|
||||
|
@ -72,7 +72,7 @@ void MessagesModel::loadMessages(const QList<int> feed_ids) {
|
||||
|
||||
if (feed_ids.size() == 1 && feed_ids[0] == ID_RECYCLE_BIN) {
|
||||
m_messageMode = MessagesFromRecycleBin;
|
||||
setFilter("is_deleted = 1");
|
||||
setFilter("is_deleted = 1 AND is_pdeleted = 0");
|
||||
}
|
||||
else {
|
||||
m_messageMode = MessagesFromFeeds;
|
||||
@ -389,7 +389,8 @@ bool MessagesModel::setBatchMessagesDeleted(const QModelIndexList &messages, int
|
||||
QString::number(deleted));
|
||||
}
|
||||
else {
|
||||
sql_delete_query = QString("DELETE FROM Messages WHERE id in (%1);").arg(message_ids.join(", "));
|
||||
sql_delete_query = QString("UPDATE Messages SET is_pdeleted = %2 WHERE id IN (%1);").arg(message_ids.join(", "),
|
||||
QString::number(deleted));
|
||||
}
|
||||
|
||||
if (query_read_msg.exec(sql_delete_query)) {
|
||||
|
@ -92,8 +92,8 @@
|
||||
#define APP_DB_SQLITE_FILE "database.db"
|
||||
|
||||
// Keep this in sync with schema versions declared in SQL initialization code.
|
||||
#define APP_DB_SCHEMA_VERSION "0.0.2"
|
||||
#define APP_DB_UPDATE_FILE_PATTERN "data_update_%1_%2_3.sql"
|
||||
#define APP_DB_SCHEMA_VERSION "2"
|
||||
#define APP_DB_UPDATE_FILE_PATTERN "db_update_%1_%2_%3.sql"
|
||||
#define APP_DB_COMMENT_SPLIT "-- !\n"
|
||||
#define APP_DB_WEB_PATH "data/database/web"
|
||||
|
||||
|
@ -77,11 +77,6 @@ void FormCategoryDetails::setEditableCategory(FeedsModelCategory *editable_categ
|
||||
}
|
||||
|
||||
int FormCategoryDetails::exec(FeedsModelCategory *input_category, FeedsModelRootItem *parent_to_select) {
|
||||
// TODO: řeseni bugu #92. pridal sem parametr parent_to_select
|
||||
// kde volajici preda pointer na doporuceny nadrazeny prvek,
|
||||
// nebo null pokud nic nedoporucuje.
|
||||
// vybereme
|
||||
|
||||
// Load categories.
|
||||
loadCategories(m_feedsModel->allCategories().values(), m_feedsModel->rootItem(), input_category);
|
||||
|
||||
|
@ -223,7 +223,6 @@ void FormSettings::saveFeedsMessages() {
|
||||
settings->setValue(APP_CFG_MESSAGES, "custom_date_format",
|
||||
m_ui->m_cmbMessagesDateTimeFormat->itemData(m_ui->m_cmbMessagesDateTimeFormat->currentIndex()).toString());
|
||||
|
||||
// TODO: aktualizovat messageview s novym formatem
|
||||
qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->updateAutoUpdateStatus();
|
||||
qApp->mainForm()->tabWidget()->feedMessageViewer()->feedsView()->sourceModel()->reloadWholeLayout();
|
||||
qApp->mainForm()->tabWidget()->feedMessageViewer()->messagesView()->sourceModel()->updateDateFormat();
|
||||
|
@ -233,8 +233,7 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c
|
||||
// Folders are created. Create new QSQLDatabase object.
|
||||
QSqlDatabase database;
|
||||
|
||||
database = QSqlDatabase::addDatabase(APP_DB_SQLITE_DRIVER,
|
||||
connection_name);
|
||||
database = QSqlDatabase::addDatabase(APP_DB_SQLITE_DRIVER, connection_name);
|
||||
database.setDatabaseName(db_file.fileName());
|
||||
|
||||
if (!database.open()) {
|
||||
@ -289,15 +288,15 @@ QSqlDatabase DatabaseFactory::sqliteInitializeFileBasedDatabase(const QString &c
|
||||
|
||||
QString installed_db_schema = query_db.value(0).toString();
|
||||
|
||||
if (!updateDatabaseSchema(installed_db_schema)) {
|
||||
if (!updateDatabaseSchema(database, installed_db_schema)) {
|
||||
qFatal("Database schema was not updated from '%s' to '%s' successully.",
|
||||
qPrintable(installed_db_schema),
|
||||
qPrintable(APP_DB_SCHEMA_VERSION));
|
||||
APP_DB_SCHEMA_VERSION);
|
||||
}
|
||||
else {
|
||||
qDebug("Database schema was updated from '%s' to '%s' successully.",
|
||||
qPrintable(installed_db_schema),
|
||||
qPrintable(APP_DB_SCHEMA_VERSION));
|
||||
APP_DB_SCHEMA_VERSION);
|
||||
}
|
||||
|
||||
qDebug("File-based SQLite database connection '%s' to file '%s' seems to be established.",
|
||||
@ -319,20 +318,93 @@ QString DatabaseFactory::sqliteDatabaseFilePath() const {
|
||||
return m_sqliteDatabaseFilePath + QDir::separator() + APP_DB_SQLITE_FILE;
|
||||
}
|
||||
|
||||
bool DatabaseFactory::updateDatabaseSchema(const QString &source_db_schema_version) {
|
||||
bool DatabaseFactory::updateDatabaseSchema(QSqlDatabase database, const QString &source_db_schema_version) {
|
||||
switch (m_activeDatabaseDriver) {
|
||||
case SQLITE:
|
||||
case SQLITE_MEMORY:
|
||||
break;
|
||||
return sqliteUpdateDatabaseSchema(database, source_db_schema_version);
|
||||
|
||||
case MYSQL:
|
||||
break;
|
||||
return mysqlUpdateDatabaseSchema(database, source_db_schema_version);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DatabaseFactory::sqliteUpdateDatabaseSchema(QSqlDatabase database, const QString &source_db_schema_version) {
|
||||
int working_version = QString(source_db_schema_version).remove('.').toInt();
|
||||
int current_version = QString(APP_DB_SCHEMA_VERSION).remove('.').toInt();
|
||||
|
||||
while (working_version != current_version) {
|
||||
QString update_file_name = QString(APP_MISC_PATH) + QDir::separator() +
|
||||
QString(APP_DB_UPDATE_FILE_PATTERN).arg("sqlite",
|
||||
QString::number(working_version),
|
||||
QString::number(working_version + 1));
|
||||
|
||||
if (!QFile::exists(update_file_name)) {
|
||||
qFatal("Updating of database schema failed. File '%s' does not exist.", qPrintable(QDir::toNativeSeparators(update_file_name)));
|
||||
}
|
||||
|
||||
QFile update_file_handle(update_file_name);
|
||||
|
||||
if (!update_file_handle.open(QIODevice::Text | QIODevice::ReadOnly | QIODevice::Unbuffered)) {
|
||||
qFatal("Updating of database schema failed. File '%s' cannot be opened.", qPrintable(QDir::toNativeSeparators(update_file_name)));
|
||||
}
|
||||
|
||||
QStringList statements = QString(update_file_handle.readAll()).split(APP_DB_COMMENT_SPLIT, QString::SkipEmptyParts);
|
||||
|
||||
foreach (const QString &statement, statements) {
|
||||
QSqlQuery query = database.exec(statement);
|
||||
|
||||
if (query.lastError().isValid()) {
|
||||
qFatal("Query for updating database schema failed: '%s'.", qPrintable(query.lastError().text()));
|
||||
}
|
||||
}
|
||||
|
||||
// Increment the version.
|
||||
qDebug("Updating database schema: '%d' -> '%d'.", working_version, working_version + 1);
|
||||
working_version++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DatabaseFactory::mysqlUpdateDatabaseSchema(QSqlDatabase database, const QString &source_db_schema_version) {
|
||||
int working_version = QString(source_db_schema_version).remove('.').toInt();
|
||||
int current_version = QString(APP_DB_SCHEMA_VERSION).remove('.').toInt();
|
||||
|
||||
while (working_version != current_version) {
|
||||
QString update_file_name = QString(APP_MISC_PATH) + QDir::separator() +
|
||||
QString(APP_DB_UPDATE_FILE_PATTERN).arg("mysql",
|
||||
QString::number(working_version),
|
||||
QString::number(working_version + 1));
|
||||
|
||||
if (!QFile::exists(update_file_name)) {
|
||||
qFatal("Updating of database schema failed. File '%s' does not exist.", qPrintable(QDir::toNativeSeparators(update_file_name)));
|
||||
}
|
||||
|
||||
QFile update_file_handle(update_file_name);
|
||||
|
||||
if (!update_file_handle.open(QIODevice::Text | QIODevice::ReadOnly | QIODevice::Unbuffered)) {
|
||||
qFatal("Updating of database schema failed. File '%s' cannot be opened.", qPrintable(QDir::toNativeSeparators(update_file_name)));
|
||||
}
|
||||
|
||||
QStringList statements = QString(update_file_handle.readAll()).split(APP_DB_COMMENT_SPLIT, QString::SkipEmptyParts);
|
||||
|
||||
foreach (const QString &statement, statements) {
|
||||
QSqlQuery query = database.exec(statement);
|
||||
|
||||
if (query.lastError().isValid()) {
|
||||
qFatal("Query for updating database schema failed: '%s'.", qPrintable(query.lastError().text()));
|
||||
}
|
||||
}
|
||||
|
||||
// Increment the version.
|
||||
qDebug("Updating database schema: '%d' -> '%d'.", working_version, working_version + 1);
|
||||
working_version++;
|
||||
}
|
||||
|
||||
// TODO: tady udělat update databázového schématu na novou verzi.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,6 @@ class DatabaseFactory : public QObject {
|
||||
// SQLITE stuff.
|
||||
//
|
||||
QString sqliteDatabaseFilePath() const;
|
||||
bool updateDatabaseSchema(const QString &source_db_schema_version);
|
||||
|
||||
//
|
||||
// MySQL stuff.
|
||||
@ -108,6 +107,8 @@ class DatabaseFactory : public QObject {
|
||||
// application session.
|
||||
void determineDriver();
|
||||
|
||||
bool updateDatabaseSchema(QSqlDatabase database, const QString &source_db_schema_version);
|
||||
|
||||
// Holds the type of currently activated database backend.
|
||||
UsedDriver m_activeDatabaseDriver;
|
||||
|
||||
@ -121,6 +122,9 @@ class DatabaseFactory : public QObject {
|
||||
// Initializes MySQL database.
|
||||
QSqlDatabase mysqlInitializeDatabase(const QString &connection_name);
|
||||
|
||||
// Updates database schema.
|
||||
bool mysqlUpdateDatabaseSchema(QSqlDatabase database, const QString &source_db_schema_version);
|
||||
|
||||
// Runs "VACUUM" on the database.
|
||||
bool mysqlVacuumDatabase();
|
||||
|
||||
@ -144,6 +148,9 @@ class DatabaseFactory : public QObject {
|
||||
// Assemblies database file path.
|
||||
void sqliteAssemblyDatabaseFilePath();
|
||||
|
||||
// Updates database schema.
|
||||
bool sqliteUpdateDatabaseSchema(QSqlDatabase database, const QString &source_db_schema_version);
|
||||
|
||||
// Creates new connection, initializes database and
|
||||
// returns opened connections.
|
||||
QSqlDatabase sqliteInitializeInMemoryDatabase();
|
||||
|
Loading…
x
Reference in New Issue
Block a user