DB refactoring.

This commit is contained in:
Martin Rotter 2015-12-20 19:02:29 +01:00
parent 1a411c7685
commit dd1d7be8b0
11 changed files with 81 additions and 146 deletions

View File

@ -33,7 +33,6 @@
MessagesModel::MessagesModel(QObject *parent) MessagesModel::MessagesModel(QObject *parent)
: QSqlTableModel(parent, qApp->database()->connection(QSL("MessagesModel"), DatabaseFactory::FromSettings)), : QSqlTableModel(parent, qApp->database()->connection(QSL("MessagesModel"), DatabaseFactory::FromSettings)),
m_messageHighlighter(NoHighlighting), m_customDateFormat(QString()) { m_messageHighlighter(NoHighlighting), m_customDateFormat(QString()) {
setObjectName(QSL("MessagesModel"));
setupFonts(); setupFonts();
setupIcons(); setupIcons();
setupHeaderData(); setupHeaderData();

View File

@ -273,7 +273,7 @@ void FeedsView::openSelectedItemsInNewspaperMode() {
if (!messages.isEmpty()) { if (!messages.isEmpty()) {
emit openMessagesInNewspaperView(messages); emit openMessagesInNewspaperView(messages);
QTimer::singleShot(0, this, SLOT(markSelectedItemRead())); QTimer::singleShot(150, this, SLOT(markSelectedItemRead()));
} }
} }

View File

@ -27,7 +27,6 @@
DatabaseCleaner::DatabaseCleaner(QObject *parent) : QObject(parent) { DatabaseCleaner::DatabaseCleaner(QObject *parent) : QObject(parent) {
setObjectName("DatabaseCleaner");
} }
DatabaseCleaner::~DatabaseCleaner() { DatabaseCleaner::~DatabaseCleaner() {
@ -42,7 +41,7 @@ void DatabaseCleaner::purgeDatabaseData(const CleanerOrders &which_data) {
bool result = true; bool result = true;
int difference = 99 / 8; int difference = 99 / 8;
int progress = 0; int progress = 0;
QSqlDatabase database = qApp->database()->connection(objectName(), DatabaseFactory::FromSettings); QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
if (which_data.m_removeReadMessages) { if (which_data.m_removeReadMessages) {
progress += difference; progress += difference;

View File

@ -41,8 +41,7 @@ DatabaseFactory::~DatabaseFactory() {
qint64 DatabaseFactory::getDatabaseSize() { qint64 DatabaseFactory::getDatabaseSize() {
if (m_activeDatabaseDriver == SQLITE || m_activeDatabaseDriver == SQLITE_MEMORY) { if (m_activeDatabaseDriver == SQLITE || m_activeDatabaseDriver == SQLITE_MEMORY) {
qint64 size = QFileInfo(sqliteDatabaseFilePath()).size(); return QFileInfo(sqliteDatabaseFilePath()).size();
return size;
} }
else { else {
return 0; return 0;

View File

@ -60,6 +60,7 @@ class DatabaseFactory : public QObject {
// Destructor. // Destructor.
virtual ~DatabaseFactory(); virtual ~DatabaseFactory();
// Returns size of DB file.
qint64 getDatabaseSize(); qint64 getDatabaseSize();
// If in-memory is true, then :memory: database is returned // If in-memory is true, then :memory: database is returned

View File

@ -118,35 +118,17 @@ QList<Message> RecycleBin::undeletedMessages() const {
bool RecycleBin::markAsReadUnread(RootItem::ReadStatus status) { bool RecycleBin::markAsReadUnread(RootItem::ReadStatus status) {
QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
if (!db_handle.transaction()) {
qWarning("Starting transaction for recycle bin read change.");
return false;
}
QSqlQuery query_read_msg(db_handle); QSqlQuery query_read_msg(db_handle);
ServiceRoot *parent_root = getParentServiceRoot(); ServiceRoot *parent_root = getParentServiceRoot();
query_read_msg.setForwardOnly(true); query_read_msg.setForwardOnly(true);
query_read_msg.prepare("UPDATE Messages SET is_read = :read "
if (!query_read_msg.prepare("UPDATE Messages SET is_read = :read " "WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;");
"WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;")) {
qWarning("Query preparation failed for recycle bin read change.");
db_handle.rollback();
return false;
}
query_read_msg.bindValue(QSL(":read"), status == RootItem::Read ? 1 : 0); query_read_msg.bindValue(QSL(":read"), status == RootItem::Read ? 1 : 0);
query_read_msg.bindValue(QSL(":account_id"), parent_root->accountId()); query_read_msg.bindValue(QSL(":account_id"), parent_root->accountId());
if (!query_read_msg.exec()) { if (query_read_msg.exec()) {
qDebug("Query execution for recycle bin read change failed.");
db_handle.rollback();
}
// Commit changes.
if (db_handle.commit()) {
updateCounts(false); updateCounts(false);
parent_root->itemChanged(QList<RootItem*>() << this); parent_root->itemChanged(QList<RootItem*>() << this);
@ -154,18 +136,12 @@ bool RecycleBin::markAsReadUnread(RootItem::ReadStatus status) {
return true; return true;
} }
else { else {
return db_handle.rollback(); return false;
} }
} }
bool RecycleBin::cleanMessages(bool clear_only_read) { bool RecycleBin::cleanMessages(bool clear_only_read) {
QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
if (!db_handle.transaction()) {
qWarning("Starting transaction for recycle bin emptying.");
return false;
}
ServiceRoot *parent_root = getParentServiceRoot(); ServiceRoot *parent_root = getParentServiceRoot();
QSqlQuery query_empty_bin(db_handle); QSqlQuery query_empty_bin(db_handle);
@ -181,22 +157,14 @@ bool RecycleBin::cleanMessages(bool clear_only_read) {
query_empty_bin.bindValue(QSL(":account_id"), parent_root->accountId()); query_empty_bin.bindValue(QSL(":account_id"), parent_root->accountId());
if (!query_empty_bin.exec()) { if (query_empty_bin.exec()) {
qWarning("Query execution failed for recycle bin emptying.");
db_handle.rollback();
return false;
}
// Commit changes.
if (db_handle.commit()) {
updateCounts(true); updateCounts(true);
parent_root->itemChanged(QList<RootItem*>() << this); parent_root->itemChanged(QList<RootItem*>() << this);
parent_root->requestReloadMessageList(true); parent_root->requestReloadMessageList(true);
return true; return true;;
} }
else { else {
return db_handle.rollback(); return false;
} }
} }
@ -206,12 +174,6 @@ bool RecycleBin::empty() {
bool RecycleBin::restore() { bool RecycleBin::restore() {
QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
if (!db_handle.transaction()) {
qWarning("Starting transaction for recycle bin restoring.");
return false;
}
ServiceRoot *parent_root = getParentServiceRoot(); ServiceRoot *parent_root = getParentServiceRoot();
QSqlQuery query_empty_bin(db_handle); QSqlQuery query_empty_bin(db_handle);
@ -220,15 +182,7 @@ bool RecycleBin::restore() {
"WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;"); "WHERE is_deleted = 1 AND is_pdeleted = 0 AND account_id = :account_id;");
query_empty_bin.bindValue(QSL(":account_id"), parent_root->accountId()); query_empty_bin.bindValue(QSL(":account_id"), parent_root->accountId());
if (!query_empty_bin.exec()) { if (query_empty_bin.exec()) {
qWarning("Query execution failed for recycle bin restoring.");
db_handle.rollback();
return false;
}
// Commit changes.
if (db_handle.commit()) {
parent_root->updateCounts(true); parent_root->updateCounts(true);
parent_root->itemChanged(parent_root->getSubTree()); parent_root->itemChanged(parent_root->getSubTree());
parent_root->requestReloadMessageList(true); parent_root->requestReloadMessageList(true);
@ -236,6 +190,6 @@ bool RecycleBin::restore() {
return true; return true;
} }
else { else {
return db_handle.rollback(); return false;
} }
} }

View File

@ -23,6 +23,7 @@
#include "services/abstract/category.h" #include "services/abstract/category.h"
#include <QSqlQuery> #include <QSqlQuery>
#include <QSqlError>
ServiceRoot::ServiceRoot(RootItem *parent) : RootItem(parent), m_accountId(NO_PARENT_CATEGORY) { ServiceRoot::ServiceRoot(RootItem *parent) : RootItem(parent), m_accountId(NO_PARENT_CATEGORY) {
@ -34,61 +35,50 @@ ServiceRoot::~ServiceRoot() {
bool ServiceRoot::deleteViaGui() { bool ServiceRoot::deleteViaGui() {
QSqlDatabase connection = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlDatabase connection = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
QSqlQuery query(connection);
int account_id = accountId();
query.setForwardOnly(true);
// Remove all messages. QStringList queries;
if (!QSqlQuery(connection).exec(QString("DELETE FROM Messages WHERE account_id = %1;").arg(accountId()))) { queries << QSL("DELETE FROM Messages WHERE account_id = :account_id;") <<
return false; QSL("DELETE FROM Feeds WHERE account_id = :account_id;") <<
QSL("DELETE FROM Categories WHERE account_id = :account_id;") <<
QSL("DELETE FROM Accounts WHERE id = :account_id;");
foreach (const QString &q, queries) {
query.prepare(q);
query.bindValue(QSL(":account_id"), account_id);
if (!query.exec()) {
qCritical("Removing of account from DB failed, this is critical: '%s'.", qPrintable(query.lastError().text()));
return false;
}
else {
query.finish();
}
} }
// Remove all feeds. requestItemRemoval(this);
if (!QSqlQuery(connection).exec(QString("DELETE FROM Feeds WHERE account_id = %1;").arg(accountId()))) { return true;
return false;
}
// Remove all categories.
if (!QSqlQuery(connection).exec(QString("DELETE FROM Categories WHERE account_id = %1;").arg(accountId()))) {
return false;
}
// Switch "existence" flag.
bool data_removed = QSqlQuery(connection).exec(QString("DELETE FROM Accounts WHERE id = %1;").arg(accountId()));
if (data_removed) {
requestItemRemoval(this);
}
return data_removed;
} }
bool ServiceRoot::markAsReadUnread(RootItem::ReadStatus status) { bool ServiceRoot::markAsReadUnread(RootItem::ReadStatus status) {
QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
QSqlQuery query(db_handle);
query.setForwardOnly(true);
query.prepare(QSL("UPDATE Messages SET is_read = :read WHERE is_pdeleted = 0 AND account_id = :account_id;"));
if (!db_handle.transaction()) { query.bindValue(QSL(":account_id"), accountId());
qWarning("Starting transaction for feeds read change."); query.bindValue(QSL(":read"), status == RootItem::Read ? 1 : 0);
return false;
}
QSqlQuery query_read_msg(db_handle); if (query.exec()) {
query_read_msg.setForwardOnly(true);
query_read_msg.prepare(QSL("UPDATE Messages SET is_read = :read WHERE is_pdeleted = 0 AND account_id = :account_id;"));
query_read_msg.bindValue(QSL(":account_id"), accountId());
query_read_msg.bindValue(QSL(":read"), status == RootItem::Read ? 1 : 0);
if (!query_read_msg.exec()) {
qDebug("Query execution for feeds read change failed.");
db_handle.rollback();
}
// Commit changes.
if (db_handle.commit()) {
updateCounts(false); updateCounts(false);
itemChanged(getSubTree()); itemChanged(getSubTree());
requestReloadMessageList(status == RootItem::Read); requestReloadMessageList(status == RootItem::Read);
return true; return true;
} }
else { else {
return db_handle.rollback(); return false;
} }
} }
@ -96,20 +86,18 @@ QList<Message> ServiceRoot::undeletedMessages() const {
QList<Message> messages; QList<Message> messages;
int account_id = accountId(); int account_id = accountId();
QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
QSqlQuery query_read_msg(database); QSqlQuery query(database);
query_read_msg.setForwardOnly(true); query.setForwardOnly(true);
query_read_msg.prepare("SELECT * " query.prepare("SELECT * "
"FROM Messages " "FROM Messages "
"WHERE is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;"); "WHERE is_deleted = 0 AND is_pdeleted = 0 AND account_id = :account_id;");
query_read_msg.bindValue(QSL(":account_id"), account_id); query.bindValue(QSL(":account_id"), account_id);
// FIXME: Fix those const functions, this is fucking ugly. if (query.exec()) {
while (query.next()) {
if (query_read_msg.exec()) {
while (query_read_msg.next()) {
bool decoded; bool decoded;
Message message = Message::fromSqlRecord(query_read_msg.record(), &decoded); Message message = Message::fromSqlRecord(query.record(), &decoded);
if (decoded) { if (decoded) {
messages.append(message); messages.append(message);

View File

@ -173,14 +173,13 @@ bool StandardCategory::addItself(RootItem *parent) {
query_add.bindValue(QSL(":account_id"), parent->getParentServiceRoot()->accountId()); query_add.bindValue(QSL(":account_id"), parent->getParentServiceRoot()->accountId());
if (!query_add.exec()) { if (!query_add.exec()) {
qDebug("Failed to add category to database: %s.", qPrintable(query_add.lastError().text())); qDebug("Failed to add category to database: '%s'.", qPrintable(query_add.lastError().text()));
// Query failed. // Query failed.
return false; return false;
} }
setId(query_add.lastInsertId().toInt()); setId(query_add.lastInsertId().toInt());
return true; return true;
} }

View File

@ -227,21 +227,26 @@ QString StandardFeed::typeToString(StandardFeed::Type type) {
void StandardFeed::updateCounts(bool including_total_count) { void StandardFeed::updateCounts(bool including_total_count) {
QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
QSqlQuery query_all(database); QSqlQuery query(database);
query.setForwardOnly(true);
query_all.setForwardOnly(true);
if (including_total_count) { if (including_total_count) {
if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = '%1' AND is_deleted = 0 AND account_id = %2;").arg(QString::number(id()), query.prepare(QSL("SELECT count(*) FROM Messages WHERE feed = :feed AND is_pdeleted = 0 AND is_deleted = 0 AND account_id = :account_id;"));
QString::number(const_cast<StandardFeed*>(this)->serviceRoot()->accountId()))) && query_all.next()) { query.bindValue(QSL(":feed"), id());
m_totalCount = query_all.value(0).toInt(); query.bindValue(QSL(":account_id"), serviceRoot()->accountId());
if (query.exec() && query.next()) {
m_totalCount = query.value(0).toInt();
} }
} }
// Obtain count of unread messages. // Obtain count of unread messages.
if (query_all.exec(QString("SELECT count(*) FROM Messages WHERE feed = '%1' AND is_deleted = 0 AND is_read = 0 AND account_id = %2;").arg(QString::number(id()), query.prepare(QSL("SELECT count(*) FROM Messages WHERE feed = :feed AND is_pdeleted = 0 AND is_deleted = 0 AND is_read = 0 AND account_id = :account_id;"));
QString::number(const_cast<StandardFeed*>(this)->serviceRoot()->accountId()))) && query_all.next()) { query.bindValue(QSL(":feed"), id());
int new_unread_count = query_all.value(0).toInt(); query.bindValue(QSL(":account_id"), serviceRoot()->accountId());
if (query.exec() && query.next()) {
int new_unread_count = query.value(0).toInt();
if (status() == NewMessages && new_unread_count < m_unreadCount) { if (status() == NewMessages && new_unread_count < m_unreadCount) {
setStatus(Normal); setStatus(Normal);
@ -544,7 +549,7 @@ bool StandardFeed::addItself(RootItem *parent) {
query_add_feed.bindValue(QSL(":type"), (int) type()); query_add_feed.bindValue(QSL(":type"), (int) type());
if (!query_add_feed.exec()) { if (!query_add_feed.exec()) {
qDebug("Failed to add feed to database: %s.", qPrintable(query_add_feed.lastError().text())); qDebug("Failed to add feed to database: '%s'.", qPrintable(query_add_feed.lastError().text()));
// Query failed. // Query failed.
return false; return false;
@ -641,7 +646,7 @@ int StandardFeed::updateMessages(const QList<Message> &messages) {
if (!database.transaction()) { if (!database.transaction()) {
database.rollback(); database.rollback();
qDebug("Transaction start for message downloader failed."); qDebug("Transaction start for message downloader failed: '%s'.", qPrintable(database.lastError().text()));
return updated_messages; return updated_messages;
} }
@ -692,7 +697,6 @@ int StandardFeed::updateMessages(const QList<Message> &messages) {
} }
query_insert.finish(); query_insert.finish();
qDebug("Adding new message '%s' to DB.", qPrintable(message.m_title)); qDebug("Adding new message '%s' to DB.", qPrintable(message.m_title));
} }
else if (message.m_createdFromFeed && !datetime_stamps.contains(message.m_created.toMSecsSinceEpoch())) { else if (message.m_createdFromFeed && !datetime_stamps.contains(message.m_created.toMSecsSinceEpoch())) {
@ -704,7 +708,6 @@ int StandardFeed::updateMessages(const QList<Message> &messages) {
query_update.bindValue(QSL(":enclosures"), Enclosures::encodeEnclosuresToString(message.m_enclosures)); query_update.bindValue(QSL(":enclosures"), Enclosures::encodeEnclosuresToString(message.m_enclosures));
query_update.exec(); query_update.exec();
query_update.finish(); query_update.finish();
qDebug("Updating contents of duplicate message '%s'.", qPrintable(message.m_title)); qDebug("Updating contents of duplicate message '%s'.", qPrintable(message.m_title));
} }
else { else {
@ -723,7 +726,6 @@ int StandardFeed::updateMessages(const QList<Message> &messages) {
} }
query_insert.finish(); query_insert.finish();
qDebug("Adding new duplicate (with potentially updated contents) message '%s' to DB.", qPrintable(message.m_title)); qDebug("Adding new duplicate (with potentially updated contents) message '%s' to DB.", qPrintable(message.m_title));
} }
} }
@ -735,7 +737,6 @@ int StandardFeed::updateMessages(const QList<Message> &messages) {
if (!database.commit()) { if (!database.commit()) {
database.rollback(); database.rollback();
qDebug("Transaction commit for message downloader failed."); qDebug("Transaction commit for message downloader failed.");
} }
else { else {
@ -768,7 +769,6 @@ StandardFeed::StandardFeed(const QSqlRecord &record) : Feed(NULL) {
setPassword(TextFactory::decrypt(record.value(FDS_DB_PASSWORD_INDEX).toString())); setPassword(TextFactory::decrypt(record.value(FDS_DB_PASSWORD_INDEX).toString()));
} }
setAutoUpdateType(static_cast<Feed::AutoUpdateType>(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); setAutoUpdateType(static_cast<Feed::AutoUpdateType>(record.value(FDS_DB_UPDATE_TYPE_INDEX).toInt()));
setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); setAutoUpdateInitialInterval(record.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt());
} }

View File

@ -71,8 +71,11 @@ ServiceRoot *StandardServiceEntryPoint::createNewRoot() {
int id_to_assign = query.value(0).toInt() + 1; int id_to_assign = query.value(0).toInt() + 1;
if (query.exec(QString("INSERT INTO Accounts (id, type) VALUES (%1, '%2');").arg(QString::number(id_to_assign), query.prepare(QSL("INSERT INTO Accounts (id, type) VALUES (:id, :type);"));
SERVICE_CODE_STD_RSS))) { query.bindValue(QSL(":id"), id_to_assign);
query.bindValue(QSL(":type"), SERVICE_CODE_STD_RSS);
if (query.exec()) {
StandardServiceRoot *root = new StandardServiceRoot(); StandardServiceRoot *root = new StandardServiceRoot();
root->setAccountId(id_to_assign); root->setAccountId(id_to_assign);
return root; return root;
@ -88,7 +91,11 @@ QList<ServiceRoot*> StandardServiceEntryPoint::initializeSubtree() {
QSqlQuery query(database); QSqlQuery query(database);
QList<ServiceRoot*> roots; QList<ServiceRoot*> roots;
if (query.exec(QString("SELECT id FROM Accounts WHERE type = '%1';").arg(SERVICE_CODE_STD_RSS))) { query.setForwardOnly(true);
query.prepare(QSL("SELECT id FROM Accounts WHERE type = :type;"));
query.bindValue(QSL(":type"), SERVICE_CODE_STD_RSS);
if (query.exec()) {
while (query.next()) { while (query.next()) {
StandardServiceRoot *root = new StandardServiceRoot(); StandardServiceRoot *root = new StandardServiceRoot();
root->setAccountId(query.value(0).toInt()); root->setAccountId(query.value(0).toInt());

View File

@ -149,22 +149,11 @@ RecycleBin *StandardServiceRoot::recycleBin() {
bool StandardServiceRoot::markFeedsReadUnread(QList<Feed*> items, ReadStatus read) { bool StandardServiceRoot::markFeedsReadUnread(QList<Feed*> items, ReadStatus read) {
QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings); QSqlDatabase db_handle = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
if (!db_handle.transaction()) {
qWarning("Starting transaction for feeds read change.");
return false;
}
QSqlQuery query_read_msg(db_handle); QSqlQuery query_read_msg(db_handle);
query_read_msg.setForwardOnly(true); query_read_msg.setForwardOnly(true);
if (!query_read_msg.prepare(QString("UPDATE Messages SET is_read = :read " query_read_msg.prepare(QString("UPDATE Messages SET is_read = :read "
"WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0;").arg(textualFeedIds(items).join(QSL(", "))))) { "WHERE feed IN (%1) AND is_deleted = 0 AND is_pdeleted = 0;").arg(textualFeedIds(items).join(QSL(", "))));
qWarning("Query preparation failed for feeds read change.");
db_handle.rollback();
return false;
}
query_read_msg.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0); query_read_msg.bindValue(QSL(":read"), read == RootItem::Read ? 1 : 0);