X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fsqlitestorage.cpp;h=026b4dc6f3e77e70c928c6e6738db5aebf339e4c;hp=909c8177e29b4fff11d15cbce6fc3a040463db6e;hb=a95ad2de573027f9bee36db972bcae4195168d0c;hpb=cc6e7c08709c4e761e2fd9c2e322751015497003 diff --git a/src/core/sqlitestorage.cpp b/src/core/sqlitestorage.cpp index 909c8177..026b4dc6 100644 --- a/src/core/sqlitestorage.cpp +++ b/src/core/sqlitestorage.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2019 by the Quassel Project * + * Copyright (C) 2005-2020 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -20,7 +20,10 @@ #include "sqlitestorage.h" -#include +#include +#include +#include +#include #include "network.h" #include "quassel.h" @@ -75,21 +78,39 @@ int SqliteStorage::installedSchemaVersion() return AbstractSqlStorage::installedSchemaVersion(); } -bool SqliteStorage::updateSchemaVersion(int newVersion) +bool SqliteStorage::updateSchemaVersion(int newVersion, bool clearUpgradeStep) { // only used when there is a singlethread (during startup) // so we don't need locking here - QSqlQuery query(logDb()); + + QSqlDatabase db = logDb(); + + // Atomically update the schema version and clear the upgrade step, if specified + // Note: This will need reworked if "updateSchemaVersion" is ever called within a transaction. + db.transaction(); + + QSqlQuery query(db); query.prepare("UPDATE coreinfo SET value = :version WHERE key = 'schemaversion'"); query.bindValue(":version", newVersion); - query.exec(); + safeExec(query); - bool success = true; - if (query.lastError().isValid()) { - qCritical() << "SqliteStorage::updateSchemaVersion(int): Updating schema version failed!"; - success = false; + if (!watchQuery(query)) { + qCritical() << "SqliteStorage::updateSchemaVersion(int, bool): Updating schema version failed!"; + db.rollback(); + return false; } - return success; + + if (clearUpgradeStep) { + // Try clearing the upgrade step if requested + if (!setSchemaVersionUpgradeStep("")) { + db.rollback(); + return false; + } + } + + // Successful, commit and return true + db.commit(); + return true; } bool SqliteStorage::setupSchemaVersion(int version) @@ -109,6 +130,52 @@ bool SqliteStorage::setupSchemaVersion(int version) return success; } +QString SqliteStorage::schemaVersionUpgradeStep() +{ + // Only used when there is a singlethread (during startup), so we don't need locking here + QSqlQuery query(logDb()); + query.prepare("SELECT value FROM coreinfo WHERE key = 'schemaupgradestep'"); + safeExec(query); + watchQuery(query); + if (query.first()) + return query.value(0).toString(); + + // Fall back to the default value + return AbstractSqlStorage::schemaVersionUpgradeStep(); +} + +bool SqliteStorage::setSchemaVersionUpgradeStep(QString upgradeQuery) +{ + // Only used when there is a singlethread (during startup), so we don't need locking here + + // Intentionally do not wrap in a transaction so other functions can include multiple operations + QSqlQuery query(logDb()); + query.prepare("UPDATE coreinfo SET value = :upgradestep WHERE key = 'schemaupgradestep'"); + query.bindValue(":upgradestep", upgradeQuery); + safeExec(query); + + // Don't wrap with watchQuery to avoid an alarming message in the log when the key is missing + // Make sure that the query didn't fail, and that some non-zero number of rows were affected + bool success = !query.lastError().isValid() && query.numRowsAffected() != 0; + + if (!success) { + // The key might not exist (Quassel 0.13.0 and older). Try inserting it... + query = QSqlQuery(logDb()); + query.prepare("INSERT INTO coreinfo (key, value) VALUES ('schemaupgradestep', :upgradestep)"); + query.bindValue(":upgradestep", upgradeQuery); + safeExec(query); + + if (!watchQuery(query)) { + qCritical() << Q_FUNC_INFO << "Setting schema upgrade step failed!"; + success = false; + } + else { + success = true; + } + } + return success; +} + UserId SqliteStorage::addUser(const QString& user, const QString& password, const QString& authenticator) { QSqlDatabase db = logDb(); @@ -128,7 +195,7 @@ UserId SqliteStorage::addUser(const QString& user, const QString& password, cons lockForWrite(); safeExec(query); if (query.lastError().isValid() - && query.lastError().number() == 19) { // user already exists - sadly 19 seems to be the general constraint violation error... + && query.lastError().nativeErrorCode() == QLatin1String{"19"}) { // user already exists - sadly 19 seems to be the general constraint violation error... db.rollback(); } else { @@ -583,9 +650,9 @@ void SqliteStorage::removeIdentity(UserId user, IdentityId identityId) unlock(); } -QList SqliteStorage::identities(UserId user) +std::vector SqliteStorage::identities(UserId user) { - QList identities; + std::vector identities; QSqlDatabase db = logDb(); db.transaction(); @@ -632,8 +699,8 @@ QList SqliteStorage::identities(UserId user) while (nickQuery.next()) { nicks << nickQuery.value(0).toString(); } - identity.setNicks(nicks); - identities << identity; + identity.setNicks(std::move(nicks)); + identities.push_back(std::move(identity)); } db.commit(); } @@ -871,9 +938,9 @@ bool SqliteStorage::removeNetwork(UserId user, const NetworkId& networkId) return true; } -QList SqliteStorage::networks(UserId user) +std::vector SqliteStorage::networks(UserId user) { - QList nets; + std::vector nets; QSqlDatabase db = logDb(); db.transaction(); @@ -941,7 +1008,7 @@ QList SqliteStorage::networks(UserId user) servers << server; } net.serverList = servers; - nets << net; + nets.push_back(std::move(net)); } } } @@ -951,9 +1018,9 @@ QList SqliteStorage::networks(UserId user) return nets; } -QList SqliteStorage::connectedNetworks(UserId user) +std::vector SqliteStorage::connectedNetworks(UserId user) { - QList connectedNets; + std::vector connectedNets; QSqlDatabase db = logDb(); db.transaction(); @@ -967,7 +1034,7 @@ QList SqliteStorage::connectedNetworks(UserId user) watchQuery(query); while (query.next()) { - connectedNets << query.value(0).toInt(); + connectedNets.emplace_back(query.value(0).toInt()); } db.commit(); } @@ -1228,9 +1295,9 @@ BufferInfo SqliteStorage::getBufferInfo(UserId user, const BufferId& bufferId) return bufferInfo; } -QList SqliteStorage::requestBuffers(UserId user) +std::vector SqliteStorage::requestBuffers(UserId user) { - QList bufferlist; + std::vector bufferlist; QSqlDatabase db = logDb(); db.transaction(); @@ -1244,11 +1311,11 @@ QList SqliteStorage::requestBuffers(UserId user) safeExec(query); watchQuery(query); while (query.next()) { - bufferlist << BufferInfo(query.value(0).toInt(), - query.value(1).toInt(), - (BufferInfo::Type)query.value(2).toInt(), - query.value(3).toInt(), - query.value(4).toString()); + bufferlist.emplace_back(query.value(0).toInt(), + query.value(1).toInt(), + (BufferInfo::Type)query.value(2).toInt(), + query.value(3).toInt(), + query.value(4).toString()); } db.commit(); } @@ -1257,9 +1324,9 @@ QList SqliteStorage::requestBuffers(UserId user) return bufferlist; } -QList SqliteStorage::requestBufferIdsForNetwork(UserId user, NetworkId networkId) +std::vector SqliteStorage::requestBufferIdsForNetwork(UserId user, NetworkId networkId) { - QList bufferList; + std::vector bufferList; QSqlDatabase db = logDb(); db.transaction(); @@ -1274,7 +1341,7 @@ QList SqliteStorage::requestBufferIdsForNetwork(UserId user, NetworkId safeExec(query); watchQuery(query); while (query.next()) { - bufferList << BufferId(query.value(0).toInt()); + bufferList.emplace_back(query.value(0).toInt()); } db.commit(); } @@ -1345,7 +1412,7 @@ bool SqliteStorage::renameBuffer(const UserId& user, const BufferId& bufferId, c error = query.lastError().isValid(); // unexepcted error occured (19 == constraint violation) - if (error && query.lastError().number() != 19) { + if (error && query.lastError().nativeErrorCode() != QLatin1String{"19"}) { watchQuery(query); } else { @@ -1726,7 +1793,7 @@ bool SqliteStorage::logMessage(Message& msg) if (logMessageQuery.lastError().isValid()) { // constraint violation - must be NOT NULL constraint - probably the sender is missing... - if (logMessageQuery.lastError().number() == 19) { + if (logMessageQuery.lastError().nativeErrorCode() == QLatin1String{"19"}) { QSqlQuery addSenderQuery(db); addSenderQuery.prepare(queryString("insert_sender")); addSenderQuery.bindValue(":sender", msg.sender()); @@ -1830,9 +1897,9 @@ bool SqliteStorage::logMessages(MessageList& msgs) return !error; } -QList SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit) +std::vector SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit) { - QList messagelist; + std::vector messagelist; QSqlDatabase db = logDb(); db.transaction(); @@ -1899,7 +1966,7 @@ QList SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId query.value(7).toString(), (Message::Flags)query.value(3).toInt()); msg.setMsgId(query.value(0).toLongLong()); - messagelist << msg; + messagelist.push_back(std::move(msg)); } } db.commit(); @@ -1908,10 +1975,10 @@ QList SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId return messagelist; } -QList SqliteStorage::requestMsgsFiltered( +std::vector SqliteStorage::requestMsgsFiltered( UserId user, BufferId bufferId, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags) { - QList messagelist; + std::vector messagelist; QSqlDatabase db = logDb(); db.transaction(); @@ -1983,7 +2050,7 @@ QList SqliteStorage::requestMsgsFiltered( query.value(7).toString(), Message::Flags{query.value(3).toInt()}); msg.setMsgId(query.value(0).toLongLong()); - messagelist << msg; + messagelist.push_back(std::move(msg)); } } db.commit(); @@ -1992,9 +2059,9 @@ QList SqliteStorage::requestMsgsFiltered( return messagelist; } -QList SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit) +std::vector SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit) { - QList messagelist; + std::vector messagelist; QSqlDatabase db = logDb(); db.transaction(); @@ -2046,7 +2113,7 @@ QList SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId las query.value(8).toString(), (Message::Flags)query.value(4).toInt()); msg.setMsgId(query.value(0).toLongLong()); - messagelist << msg; + messagelist.push_back(std::move(msg)); } } db.commit(); @@ -2054,9 +2121,9 @@ QList SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId las return messagelist; } -QList SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags) +std::vector SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags) { - QList messagelist; + std::vector messagelist; QSqlDatabase db = logDb(); db.transaction(); @@ -2113,7 +2180,7 @@ QList SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, M query.value(8).toString(), Message::Flags{query.value(4).toInt()}); msg.setMsgId(query.value(0).toLongLong()); - messagelist << msg; + messagelist.push_back(std::move(msg)); } } db.commit(); @@ -2155,15 +2222,13 @@ bool SqliteStorage::safeExec(QSqlQuery& query, int retryCount) if (!query.lastError().isValid()) return true; - switch (query.lastError().number()) { - case 5: // SQLITE_BUSY 5 /* The database file is locked */ - // fallthrough - case 6: // SQLITE_LOCKED 6 /* A table in the database is locked */ + QString nativeErrorCode = query.lastError().nativeErrorCode(); + + // SQLITE_BUSY 5 /* The database file is locked */ + // SQLITE_LOCKED 6 /* A table in the database is locked */ + if (nativeErrorCode == QLatin1String{"5"} || nativeErrorCode == QLatin1String{"6"}) { if (retryCount < _maxRetryCount) return safeExec(query, retryCount + 1); - break; - default: - ; } return false; }