X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fsqlitestorage.cpp;h=f56f914e9b339968bbf06befdce9b9a8dcf3189c;hp=e9882da334ffda0d53be6fc62cbbfb2204006922;hb=af9f6788daf6910d3727bf5a85cd88ebf0b93ba4;hpb=c0aba6b60277e5329f40513c66725dd0c52ee1b4 diff --git a/src/core/sqlitestorage.cpp b/src/core/sqlitestorage.cpp index e9882da3..f56f914e 100644 --- a/src/core/sqlitestorage.cpp +++ b/src/core/sqlitestorage.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2018 by the Quassel Project * + * Copyright (C) 2005-2019 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -22,36 +22,29 @@ #include -#include "logger.h" +#include + #include "network.h" #include "quassel.h" int SqliteStorage::_maxRetryCount = 150; -SqliteStorage::SqliteStorage(QObject *parent) +SqliteStorage::SqliteStorage(QObject* parent) : AbstractSqlStorage(parent) -{ -} - - -SqliteStorage::~SqliteStorage() -{ -} - +{} bool SqliteStorage::isAvailable() const { - if (!QSqlDatabase::isDriverAvailable("QSQLITE")) return false; + if (!QSqlDatabase::isDriverAvailable("QSQLITE")) + return false; return true; } - QString SqliteStorage::backendId() const { return QString("SQLite"); } - QString SqliteStorage::displayName() const { // Note: Pre-0.13 clients use the displayName property for backend idenfication @@ -61,7 +54,6 @@ QString SqliteStorage::displayName() const return backendId(); } - QString SqliteStorage::description() const { return tr("SQLite is a file-based database engine that does not require any setup. It is suitable for small and medium-sized " @@ -69,7 +61,6 @@ QString SqliteStorage::description() const "it is running on, and if you only expect a few users to use your core."); } - int SqliteStorage::installedSchemaVersion() { // only used when there is a singlethread (during startup) @@ -86,24 +77,40 @@ 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) { @@ -122,8 +129,53 @@ 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) +UserId SqliteStorage::addUser(const QString& user, const QString& password, const QString& authenticator) { QSqlDatabase db = logDb(); UserId uid; @@ -141,7 +193,8 @@ UserId SqliteStorage::addUser(const QString &user, const QString &password, cons query.bindValue(":authenticator", authenticator); lockForWrite(); safeExec(query); - if (query.lastError().isValid() && query.lastError().number() == 19) { // user already exists - sadly 19 seems to be the general constraint violation error... + if (query.lastError().isValid() + && query.lastError().nativeErrorCode() == QLatin1String{"19"}) { // user already exists - sadly 19 seems to be the general constraint violation error... db.rollback(); } else { @@ -156,8 +209,7 @@ UserId SqliteStorage::addUser(const QString &user, const QString &password, cons return uid; } - -bool SqliteStorage::updateUser(UserId user, const QString &password) +bool SqliteStorage::updateUser(UserId user, const QString& password) { QSqlDatabase db = logDb(); bool success = false; @@ -178,8 +230,7 @@ bool SqliteStorage::updateUser(UserId user, const QString &password) return success; } - -void SqliteStorage::renameUser(UserId user, const QString &newName) +void SqliteStorage::renameUser(UserId user, const QString& newName) { QSqlDatabase db = logDb(); db.transaction(); @@ -196,8 +247,7 @@ void SqliteStorage::renameUser(UserId user, const QString &newName) emit userRenamed(user, newName); } - -UserId SqliteStorage::validateUser(const QString &user, const QString &password) +UserId SqliteStorage::validateUser(const QString& user, const QString& password) { UserId userId; QString hashedPassword; @@ -226,8 +276,7 @@ UserId SqliteStorage::validateUser(const QString &user, const QString &password) return returnUserId; } - -UserId SqliteStorage::getUserId(const QString &username) +UserId SqliteStorage::getUserId(const QString& username) { UserId userId; @@ -288,7 +337,6 @@ UserId SqliteStorage::internalUser() return userId; } - void SqliteStorage::delUser(UserId user) { QSqlDatabase db = logDb(); @@ -320,8 +368,7 @@ void SqliteStorage::delUser(UserId user) emit userRemoved(user); } - -void SqliteStorage::setUserSetting(UserId userId, const QString &settingName, const QVariant &data) +void SqliteStorage::setUserSetting(UserId userId, const QString& settingName, const QVariant& data) { QByteArray rawData; QDataStream out(&rawData, QIODevice::WriteOnly); @@ -352,8 +399,7 @@ void SqliteStorage::setUserSetting(UserId userId, const QString &settingName, co unlock(); } - -QVariant SqliteStorage::getUserSetting(UserId userId, const QString &settingName, const QVariant &defaultData) +QVariant SqliteStorage::getUserSetting(UserId userId, const QString& settingName, const QVariant& defaultData) { QVariant data = defaultData; { @@ -375,8 +421,7 @@ QVariant SqliteStorage::getUserSetting(UserId userId, const QString &settingName return data; } - -void SqliteStorage::setCoreState(const QVariantList &data) +void SqliteStorage::setCoreState(const QVariantList& data) { QByteArray rawData; QDataStream out(&rawData, QIODevice::WriteOnly); @@ -405,8 +450,7 @@ void SqliteStorage::setCoreState(const QVariantList &data) unlock(); } - -QVariantList SqliteStorage::getCoreState(const QVariantList &defaultData) +QVariantList SqliteStorage::getCoreState(const QVariantList& defaultData) { QVariantList data; { @@ -421,7 +465,8 @@ QVariantList SqliteStorage::getCoreState(const QVariantList &defaultData) QDataStream in(&rawData, QIODevice::ReadOnly); in.setVersion(QDataStream::Qt_4_2); in >> data; - } else { + } + else { data = defaultData; } } @@ -429,8 +474,7 @@ QVariantList SqliteStorage::getCoreState(const QVariantList &defaultData) return data; } - -IdentityId SqliteStorage::createIdentity(UserId user, CoreIdentity &identity) +IdentityId SqliteStorage::createIdentity(UserId user, CoreIdentity& identity) { IdentityId identityId; @@ -481,7 +525,7 @@ IdentityId SqliteStorage::createIdentity(UserId user, CoreIdentity &identity) QSqlQuery insertNickQuery(db); insertNickQuery.prepare(queryString("insert_nick")); - foreach(QString nick, identity.nicks()) { + foreach (QString nick, identity.nicks()) { insertNickQuery.bindValue(":identityid", identityId.toInt()); insertNickQuery.bindValue(":nick", nick); safeExec(insertNickQuery); @@ -494,8 +538,7 @@ IdentityId SqliteStorage::createIdentity(UserId user, CoreIdentity &identity) return identityId; } - -bool SqliteStorage::updateIdentity(UserId user, const CoreIdentity &identity) +bool SqliteStorage::updateIdentity(UserId user, const CoreIdentity& identity) { QSqlDatabase db = logDb(); bool error = false; @@ -556,7 +599,7 @@ bool SqliteStorage::updateIdentity(UserId user, const CoreIdentity &identity) QSqlQuery insertNickQuery(db); insertNickQuery.prepare(queryString("insert_nick")); - foreach(QString nick, identity.nicks()) { + foreach (QString nick, identity.nicks()) { insertNickQuery.bindValue(":identityid", identity.id().toInt()); insertNickQuery.bindValue(":nick", nick); safeExec(insertNickQuery); @@ -568,7 +611,6 @@ bool SqliteStorage::updateIdentity(UserId user, const CoreIdentity &identity) return true; } - void SqliteStorage::removeIdentity(UserId user, IdentityId identityId) { QSqlDatabase db = logDb(); @@ -607,7 +649,6 @@ void SqliteStorage::removeIdentity(UserId user, IdentityId identityId) unlock(); } - QList SqliteStorage::identities(UserId user) { QList identities; @@ -666,8 +707,7 @@ QList SqliteStorage::identities(UserId user) return identities; } - -NetworkId SqliteStorage::createNetwork(UserId user, const NetworkInfo &info) +NetworkId SqliteStorage::createNetwork(UserId user, const NetworkInfo& info) { NetworkId networkId; @@ -692,13 +732,13 @@ NetworkId SqliteStorage::createNetwork(UserId user, const NetworkInfo &info) } if (error) { unlock(); - return NetworkId(); + return {}; } { QSqlQuery insertServersQuery(db); insertServersQuery.prepare(queryString("insert_server")); - foreach(Network::Server server, info.serverList) { + foreach (Network::Server server, info.serverList) { insertServersQuery.bindValue(":userid", user.toInt()); insertServersQuery.bindValue(":networkid", networkId.toInt()); bindServerInfo(insertServersQuery, server); @@ -714,13 +754,12 @@ NetworkId SqliteStorage::createNetwork(UserId user, const NetworkInfo &info) } unlock(); if (error) - return NetworkId(); + return {}; else return networkId; } - -void SqliteStorage::bindNetworkInfo(QSqlQuery &query, const NetworkInfo &info) +void SqliteStorage::bindNetworkInfo(QSqlQuery& query, const NetworkInfo& info) { query.bindValue(":networkname", info.networkName); query.bindValue(":identityid", info.identity.toInt()); @@ -749,8 +788,7 @@ void SqliteStorage::bindNetworkInfo(QSqlQuery &query, const NetworkInfo &info) query.bindValue(":networkid", info.networkId.toInt()); } - -void SqliteStorage::bindServerInfo(QSqlQuery &query, const Network::Server &server) +void SqliteStorage::bindServerInfo(QSqlQuery& query, const Network::Server& server) { query.bindValue(":hostname", server.host); query.bindValue(":port", server.port); @@ -766,8 +804,7 @@ void SqliteStorage::bindServerInfo(QSqlQuery &query, const Network::Server &serv query.bindValue(":sslverify", server.sslVerify ? 1 : 0); } - -bool SqliteStorage::updateNetwork(UserId user, const NetworkInfo &info) +bool SqliteStorage::updateNetwork(UserId user, const NetworkInfo& info) { QSqlDatabase db = logDb(); bool error = false; @@ -809,7 +846,7 @@ bool SqliteStorage::updateNetwork(UserId user, const NetworkInfo &info) { QSqlQuery insertServersQuery(db); insertServersQuery.prepare(queryString("insert_server")); - foreach(Network::Server server, info.serverList) { + foreach (Network::Server server, info.serverList) { insertServersQuery.bindValue(":userid", user.toInt()); insertServersQuery.bindValue(":networkid", info.networkId.toInt()); bindServerInfo(insertServersQuery, server); @@ -827,8 +864,7 @@ bool SqliteStorage::updateNetwork(UserId user, const NetworkInfo &info) return !error; } - -bool SqliteStorage::removeNetwork(UserId user, const NetworkId &networkId) +bool SqliteStorage::removeNetwork(UserId user, const NetworkId& networkId) { QSqlDatabase db = logDb(); bool error = false; @@ -901,7 +937,6 @@ bool SqliteStorage::removeNetwork(UserId user, const NetworkId &networkId) return true; } - QList SqliteStorage::networks(UserId user) { QList nets; @@ -982,7 +1017,6 @@ QList SqliteStorage::networks(UserId user) return nets; } - QList SqliteStorage::connectedNetworks(UserId user) { QList connectedNets; @@ -1007,8 +1041,7 @@ QList SqliteStorage::connectedNetworks(UserId user) return connectedNets; } - -void SqliteStorage::setNetworkConnected(UserId user, const NetworkId &networkId, bool isConnected) +void SqliteStorage::setNetworkConnected(UserId user, const NetworkId& networkId, bool isConnected) { QSqlDatabase db = logDb(); db.transaction(); @@ -1028,8 +1061,7 @@ void SqliteStorage::setNetworkConnected(UserId user, const NetworkId &networkId, unlock(); } - -QHash SqliteStorage::persistentChannels(UserId user, const NetworkId &networkId) +QHash SqliteStorage::persistentChannels(UserId user, const NetworkId& networkId) { QHash persistentChans; @@ -1052,8 +1084,7 @@ QHash SqliteStorage::persistentChannels(UserId user, const Net return persistentChans; } - -void SqliteStorage::setChannelPersistent(UserId user, const NetworkId &networkId, const QString &channel, bool isJoined) +void SqliteStorage::setChannelPersistent(UserId user, const NetworkId& networkId, const QString& channel, bool isJoined) { QSqlDatabase db = logDb(); db.transaction(); @@ -1074,8 +1105,7 @@ void SqliteStorage::setChannelPersistent(UserId user, const NetworkId &networkId unlock(); } - -void SqliteStorage::setPersistentChannelKey(UserId user, const NetworkId &networkId, const QString &channel, const QString &key) +void SqliteStorage::setPersistentChannelKey(UserId user, const NetworkId& networkId, const QString& channel, const QString& key) { QSqlDatabase db = logDb(); db.transaction(); @@ -1096,7 +1126,6 @@ void SqliteStorage::setPersistentChannelKey(UserId user, const NetworkId &networ unlock(); } - QString SqliteStorage::awayMessage(UserId user, NetworkId networkId) { QSqlDatabase db = logDb(); @@ -1121,8 +1150,7 @@ QString SqliteStorage::awayMessage(UserId user, NetworkId networkId) return awayMsg; } - -void SqliteStorage::setAwayMessage(UserId user, NetworkId networkId, const QString &awayMsg) +void SqliteStorage::setAwayMessage(UserId user, NetworkId networkId, const QString& awayMsg) { QSqlDatabase db = logDb(); db.transaction(); @@ -1142,7 +1170,6 @@ void SqliteStorage::setAwayMessage(UserId user, NetworkId networkId, const QStri unlock(); } - QString SqliteStorage::userModes(UserId user, NetworkId networkId) { QSqlDatabase db = logDb(); @@ -1167,8 +1194,7 @@ QString SqliteStorage::userModes(UserId user, NetworkId networkId) return modes; } - -void SqliteStorage::setUserModes(UserId user, NetworkId networkId, const QString &userModes) +void SqliteStorage::setUserModes(UserId user, NetworkId networkId, const QString& userModes) { QSqlDatabase db = logDb(); db.transaction(); @@ -1188,8 +1214,7 @@ void SqliteStorage::setUserModes(UserId user, NetworkId networkId, const QString unlock(); } - -BufferInfo SqliteStorage::bufferInfo(UserId user, const NetworkId &networkId, BufferInfo::Type type, const QString &buffer, bool create) +BufferInfo SqliteStorage::bufferInfo(UserId user, const NetworkId& networkId, BufferInfo::Type type, const QString& buffer, bool create) { QSqlDatabase db = logDb(); db.transaction(); @@ -1240,8 +1265,7 @@ BufferInfo SqliteStorage::bufferInfo(UserId user, const NetworkId &networkId, Bu return bufferInfo; } - -BufferInfo SqliteStorage::getBufferInfo(UserId user, const BufferId &bufferId) +BufferInfo SqliteStorage::getBufferInfo(UserId user, const BufferId& bufferId) { QSqlDatabase db = logDb(); db.transaction(); @@ -1257,7 +1281,11 @@ BufferInfo SqliteStorage::getBufferInfo(UserId user, const BufferId &bufferId) safeExec(query); if (watchQuery(query) && query.first()) { - bufferInfo = BufferInfo(query.value(0).toInt(), query.value(1).toInt(), (BufferInfo::Type)query.value(2).toInt(), 0, query.value(4).toString()); + bufferInfo = BufferInfo(query.value(0).toInt(), + query.value(1).toInt(), + (BufferInfo::Type)query.value(2).toInt(), + 0, + query.value(4).toString()); Q_ASSERT(!query.next()); } db.commit(); @@ -1266,7 +1294,6 @@ BufferInfo SqliteStorage::getBufferInfo(UserId user, const BufferId &bufferId) return bufferInfo; } - QList SqliteStorage::requestBuffers(UserId user) { QList bufferlist; @@ -1283,7 +1310,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 << BufferInfo(query.value(0).toInt(), + query.value(1).toInt(), + (BufferInfo::Type)query.value(2).toInt(), + query.value(3).toInt(), + query.value(4).toString()); } db.commit(); } @@ -1292,7 +1323,6 @@ QList SqliteStorage::requestBuffers(UserId user) return bufferlist; } - QList SqliteStorage::requestBufferIdsForNetwork(UserId user, NetworkId networkId) { QList bufferList; @@ -1319,8 +1349,7 @@ QList SqliteStorage::requestBufferIdsForNetwork(UserId user, NetworkId return bufferList; } - -bool SqliteStorage::removeBuffer(const UserId &user, const BufferId &bufferId) +bool SqliteStorage::removeBuffer(const UserId& user, const BufferId& bufferId) { QSqlDatabase db = logDb(); db.transaction(); @@ -1363,8 +1392,7 @@ bool SqliteStorage::removeBuffer(const UserId &user, const BufferId &bufferId) return !error; } - -bool SqliteStorage::renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName) +bool SqliteStorage::renameBuffer(const UserId& user, const BufferId& bufferId, const QString& newName) { QSqlDatabase db = logDb(); db.transaction(); @@ -1383,7 +1411,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 { @@ -1400,8 +1428,7 @@ bool SqliteStorage::renameBuffer(const UserId &user, const BufferId &bufferId, c return !error; } - -bool SqliteStorage::mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2) +bool SqliteStorage::mergeBuffersPermanently(const UserId& user, const BufferId& bufferId1, const BufferId& bufferId2) { QSqlDatabase db = logDb(); db.transaction(); @@ -1457,8 +1484,7 @@ bool SqliteStorage::mergeBuffersPermanently(const UserId &user, const BufferId & return !error; } - -void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId) +void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId& bufferId, const MsgId& msgId) { QSqlDatabase db = logDb(); db.transaction(); @@ -1478,7 +1504,6 @@ void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId, unlock(); } - QHash SqliteStorage::bufferLastSeenMsgIds(UserId user) { QHash lastSeenHash; @@ -1507,8 +1532,7 @@ QHash SqliteStorage::bufferLastSeenMsgIds(UserId user) return lastSeenHash; } - -void SqliteStorage::setBufferMarkerLineMsg(UserId user, const BufferId &bufferId, const MsgId &msgId) +void SqliteStorage::setBufferMarkerLineMsg(UserId user, const BufferId& bufferId, const MsgId& msgId) { QSqlDatabase db = logDb(); db.transaction(); @@ -1528,7 +1552,6 @@ void SqliteStorage::setBufferMarkerLineMsg(UserId user, const BufferId &bufferId unlock(); } - QHash SqliteStorage::bufferMarkerLineMsgIds(UserId user) { QHash markerLineHash; @@ -1567,7 +1590,7 @@ void SqliteStorage::setBufferActivity(UserId user, BufferId bufferId, Message::T query.prepare(queryString("update_buffer_bufferactivity")); query.bindValue(":userid", user.toInt()); query.bindValue(":bufferid", bufferId.toInt()); - query.bindValue(":bufferactivity", (int) bufferActivity); + query.bindValue(":bufferactivity", (int)bufferActivity); lockForWrite(); safeExec(query); @@ -1577,7 +1600,6 @@ void SqliteStorage::setBufferActivity(UserId user, BufferId bufferId, Message::T unlock(); } - QHash SqliteStorage::bufferActivities(UserId user) { QHash bufferActivityHash; @@ -1606,13 +1628,12 @@ QHash SqliteStorage::bufferActivities(UserId user) return bufferActivityHash; } - Message::Types SqliteStorage::bufferActivity(BufferId bufferId, MsgId lastSeenMsgId) { QSqlDatabase db = logDb(); db.transaction(); - Message::Types result = Message::Types(0); + Message::Types result = Message::Types(nullptr); { QSqlQuery query(db); query.prepare(queryString("select_buffer_bufferactivity")); @@ -1630,7 +1651,7 @@ Message::Types SqliteStorage::bufferActivity(BufferId bufferId, MsgId lastSeenMs return result; } -QHash SqliteStorage::bufferCiphers(UserId user, const NetworkId &networkId) +QHash SqliteStorage::bufferCiphers(UserId user, const NetworkId& networkId) { QHash bufferCiphers; @@ -1653,7 +1674,7 @@ QHash SqliteStorage::bufferCiphers(UserId user, const Netwo return bufferCiphers; } -void SqliteStorage::setBufferCipher(UserId user, const NetworkId &networkId, const QString &bufferName, const QByteArray &cipher) +void SqliteStorage::setBufferCipher(UserId user, const NetworkId& networkId, const QString& bufferName, const QByteArray& cipher) { QSqlDatabase db = logDb(); db.transaction(); @@ -1694,7 +1715,6 @@ void SqliteStorage::setHighlightCount(UserId user, BufferId bufferId, int count) unlock(); } - QHash SqliteStorage::highlightCounts(UserId user) { QHash highlightCountHash; @@ -1723,7 +1743,6 @@ QHash SqliteStorage::highlightCounts(UserId user) return highlightCountHash; } - int SqliteStorage::highlightCount(BufferId bufferId, MsgId lastSeenMsgId) { QSqlDatabase db = logDb(); @@ -1747,7 +1766,7 @@ int SqliteStorage::highlightCount(BufferId bufferId, MsgId lastSeenMsgId) return result; } -bool SqliteStorage::logMessage(Message &msg) +bool SqliteStorage::logMessage(Message& msg) { QSqlDatabase db = logDb(); db.transaction(); @@ -1756,8 +1775,9 @@ bool SqliteStorage::logMessage(Message &msg) { QSqlQuery logMessageQuery(db); logMessageQuery.prepare(queryString("insert_message")); - - logMessageQuery.bindValue(":time", msg.timestamp().toTime_t()); + // As of SQLite schema version 31, timestamps are stored in milliseconds instead of + // seconds. This nets us more precision as well as simplifying 64-bit time. + logMessageQuery.bindValue(":time", msg.timestamp().toMSecsSinceEpoch()); logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt()); logMessageQuery.bindValue(":type", msg.type()); logMessageQuery.bindValue(":flags", (int)msg.flags()); @@ -1772,7 +1792,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()); @@ -1808,8 +1828,7 @@ bool SqliteStorage::logMessage(Message &msg) return !error; } - -bool SqliteStorage::logMessages(MessageList &msgs) +bool SqliteStorage::logMessages(MessageList& msgs) { QSqlDatabase db = logDb(); db.transaction(); @@ -1820,8 +1839,8 @@ bool SqliteStorage::logMessages(MessageList &msgs) addSenderQuery.prepare(queryString("insert_sender")); lockForWrite(); for (int i = 0; i < msgs.count(); i++) { - auto &msg = msgs.at(i); - SenderData sender = { msg.sender(), msg.realName(), msg.avatarUrl() }; + auto& msg = msgs.at(i); + SenderData sender = {msg.sender(), msg.realName(), msg.avatarUrl()}; if (senders.contains(sender)) continue; senders << sender; @@ -1838,9 +1857,10 @@ bool SqliteStorage::logMessages(MessageList &msgs) QSqlQuery logMessageQuery(db); logMessageQuery.prepare(queryString("insert_message")); for (int i = 0; i < msgs.count(); i++) { - Message &msg = msgs[i]; - - logMessageQuery.bindValue(":time", msg.timestamp().toTime_t()); + Message& msg = msgs[i]; + // As of SQLite schema version 31, timestamps are stored in milliseconds instead of + // seconds. This nets us more precision as well as simplifying 64-bit time. + logMessageQuery.bindValue(":time", msg.timestamp().toMSecsSinceEpoch()); logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt()); logMessageQuery.bindValue(":type", msg.type()); logMessageQuery.bindValue(":flags", (int)msg.flags()); @@ -1876,7 +1896,6 @@ bool SqliteStorage::logMessages(MessageList &msgs) return !error; } - QList SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit) { QList messagelist; @@ -1898,7 +1917,11 @@ QList SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId safeExec(bufferInfoQuery); error = !watchQuery(bufferInfoQuery) || !bufferInfoQuery.first(); if (!error) { - bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), 0, bufferInfoQuery.value(4).toString()); + bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), + bufferInfoQuery.value(1).toInt(), + (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), + 0, + bufferInfoQuery.value(4).toString()); error = !bufferInfo.isValid(); } } @@ -1929,15 +1952,18 @@ QList SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId watchQuery(query); while (query.next()) { - Message msg(QDateTime::fromTime_t(query.value(1).toInt()), + Message msg( + // As of SQLite schema version 31, timestamps are stored in milliseconds instead of + // seconds. This nets us more precision as well as simplifying 64-bit time. + QDateTime::fromMSecsSinceEpoch(query.value(1).toLongLong()), bufferInfo, - (Message::Type)query.value(2).toUInt(), + (Message::Type)query.value(2).toInt(), query.value(8).toString(), query.value(4).toString(), query.value(5).toString(), query.value(6).toString(), query.value(7).toString(), - (Message::Flags)query.value(3).toUInt()); + (Message::Flags)query.value(3).toInt()); msg.setMsgId(query.value(0).toLongLong()); messagelist << msg; } @@ -1948,8 +1974,8 @@ QList SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId return messagelist; } - -QList SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags) +QList SqliteStorage::requestMsgsFiltered( + UserId user, BufferId bufferId, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags) { QList messagelist; @@ -1970,7 +1996,11 @@ QList SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId safeExec(bufferInfoQuery); error = !watchQuery(bufferInfoQuery) || !bufferInfoQuery.first(); if (!error) { - bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), 0, bufferInfoQuery.value(4).toString()); + bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), + bufferInfoQuery.value(1).toInt(), + (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), + 0, + bufferInfoQuery.value(4).toString()); error = !bufferInfo.isValid(); } } @@ -2005,15 +2035,19 @@ QList SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId watchQuery(query); while (query.next()) { - Message msg(QDateTime::fromTime_t(query.value(1).toInt()), - bufferInfo, - (Message::Type)query.value(2).toUInt(), - query.value(8).toString(), - query.value(4).toString(), - query.value(5).toString(), - query.value(6).toString(), - query.value(7).toString(), - Message::Flags{query.value(3).toInt()}); + Message msg( + // As of SQLite schema version 31, timestamps are stored in milliseconds + // instead of seconds. This nets us more precision as well as simplifying + // 64-bit time. + QDateTime::fromMSecsSinceEpoch(query.value(1).toLongLong()), + bufferInfo, + (Message::Type)query.value(2).toInt(), + query.value(8).toString(), + query.value(4).toString(), + query.value(5).toString(), + query.value(6).toString(), + query.value(7).toString(), + Message::Flags{query.value(3).toInt()}); msg.setMsgId(query.value(0).toLongLong()); messagelist << msg; } @@ -2024,7 +2058,6 @@ QList SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId return messagelist; } - QList SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit) { QList messagelist; @@ -2042,7 +2075,11 @@ QList SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId las safeExec(bufferInfoQuery); watchQuery(bufferInfoQuery); while (bufferInfoQuery.next()) { - BufferInfo bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), bufferInfoQuery.value(3).toInt(), bufferInfoQuery.value(4).toString()); + BufferInfo bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), + bufferInfoQuery.value(1).toInt(), + (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), + bufferInfoQuery.value(3).toInt(), + bufferInfoQuery.value(4).toString()); bufferInfoHash[bufferInfo.bufferId()] = bufferInfo; } @@ -2062,15 +2099,18 @@ QList SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId las watchQuery(query); while (query.next()) { - Message msg(QDateTime::fromTime_t(query.value(2).toInt()), + Message msg( + // As of SQLite schema version 31, timestamps are stored in milliseconds instead of + // seconds. This nets us more precision as well as simplifying 64-bit time. + QDateTime::fromMSecsSinceEpoch(query.value(2).toLongLong()), bufferInfoHash[query.value(1).toInt()], - (Message::Type)query.value(3).toUInt(), + (Message::Type)query.value(3).toInt(), query.value(9).toString(), query.value(5).toString(), query.value(6).toString(), query.value(7).toString(), query.value(8).toString(), - (Message::Flags)query.value(4).toUInt()); + (Message::Flags)query.value(4).toInt()); msg.setMsgId(query.value(0).toLongLong()); messagelist << msg; } @@ -2097,7 +2137,11 @@ QList SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, M safeExec(bufferInfoQuery); watchQuery(bufferInfoQuery); while (bufferInfoQuery.next()) { - BufferInfo bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), bufferInfoQuery.value(3).toInt(), bufferInfoQuery.value(4).toString()); + BufferInfo bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), + bufferInfoQuery.value(1).toInt(), + (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), + bufferInfoQuery.value(3).toInt(), + bufferInfoQuery.value(4).toString()); bufferInfoHash[bufferInfo.bufferId()] = bufferInfo; } @@ -2121,15 +2165,19 @@ QList SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, M watchQuery(query); while (query.next()) { - Message msg(QDateTime::fromTime_t(query.value(2).toInt()), - bufferInfoHash[query.value(1).toInt()], - (Message::Type)query.value(3).toUInt(), - query.value(9).toString(), - query.value(5).toString(), - query.value(6).toString(), - query.value(7).toString(), - query.value(8).toString(), - Message::Flags{query.value(4).toInt()}); + Message msg( + // As of SQLite schema version 31, timestamps are stored in milliseconds + // instead of seconds. This nets us more precision as well as simplifying + // 64-bit time. + QDateTime::fromMSecsSinceEpoch(query.value(2).toLongLong()), + bufferInfoHash[query.value(1).toInt()], + (Message::Type)query.value(3).toInt(), + query.value(9).toString(), + query.value(5).toString(), + query.value(6).toString(), + query.value(7).toString(), + query.value(8).toString(), + Message::Flags{query.value(4).toInt()}); msg.setMsgId(query.value(0).toLongLong()); messagelist << msg; } @@ -2161,62 +2209,35 @@ QMap SqliteStorage::getAllAuthUserNames() return authusernames; } - -QString SqliteStorage::getAuthUserName(UserId user) { - QString authusername; - QSqlQuery query(logDb()); - query.prepare(queryString("select_authusername")); - query.bindValue(":userid", user.toInt()); - - lockForRead(); - safeExec(query); - watchQuery(query); - unlock(); - - if (query.first()) { - authusername = query.value(0).toString(); - } - - return authusername; -} - - QString SqliteStorage::backlogFile() { return Quassel::configDirPath() + "quassel-storage.sqlite"; } - -bool SqliteStorage::safeExec(QSqlQuery &query, int retryCount) +bool SqliteStorage::safeExec(QSqlQuery& query, int retryCount) { query.exec(); if (!query.lastError().isValid()) return true; - switch (query.lastError().number()) { - case 5: // SQLITE_BUSY 5 /* The database file is locked */ - [[clang::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; } - // ======================================== // SqliteMigration // ======================================== SqliteMigrationReader::SqliteMigrationReader() - : SqliteStorage(), - _maxId(0) -{ -} - + : SqliteStorage() +{} void SqliteMigrationReader::setMaxId(MigrationObject mo) { @@ -2237,7 +2258,6 @@ void SqliteMigrationReader::setMaxId(MigrationObject mo) _maxId = query.value(0).toLongLong(); } - bool SqliteMigrationReader::prepareQuery(MigrationObject mo) { setMaxId(mo); @@ -2281,8 +2301,7 @@ bool SqliteMigrationReader::prepareQuery(MigrationObject mo) return exec(); } - -bool SqliteMigrationReader::readMo(QuasselUserMO &user) +bool SqliteMigrationReader::readMo(QuasselUserMO& user) { if (!next()) return false; @@ -2295,8 +2314,7 @@ bool SqliteMigrationReader::readMo(QuasselUserMO &user) return true; } - -bool SqliteMigrationReader::readMo(IdentityMO &identity) +bool SqliteMigrationReader::readMo(IdentityMO& identity) { if (!next()) return false; @@ -2325,8 +2343,7 @@ bool SqliteMigrationReader::readMo(IdentityMO &identity) return true; } - -bool SqliteMigrationReader::readMo(IdentityNickMO &identityNick) +bool SqliteMigrationReader::readMo(IdentityNickMO& identityNick) { if (!next()) return false; @@ -2337,8 +2354,7 @@ bool SqliteMigrationReader::readMo(IdentityNickMO &identityNick) return true; } - -bool SqliteMigrationReader::readMo(NetworkMO &network) +bool SqliteMigrationReader::readMo(NetworkMO& network) { if (!next()) return false; @@ -2376,8 +2392,7 @@ bool SqliteMigrationReader::readMo(NetworkMO &network) return true; } - -bool SqliteMigrationReader::readMo(BufferMO &buffer) +bool SqliteMigrationReader::readMo(BufferMO& buffer) { if (!next()) return false; @@ -2400,8 +2415,7 @@ bool SqliteMigrationReader::readMo(BufferMO &buffer) return true; } - -bool SqliteMigrationReader::readMo(SenderMO &sender) +bool SqliteMigrationReader::readMo(SenderMO& sender) { int skipSteps = 0; while (!next()) { @@ -2424,8 +2438,7 @@ bool SqliteMigrationReader::readMo(SenderMO &sender) return true; } - -bool SqliteMigrationReader::readMo(BacklogMO &backlog) +bool SqliteMigrationReader::readMo(BacklogMO& backlog) { qint64 skipSteps = 0; while (!next()) { @@ -2442,7 +2455,9 @@ bool SqliteMigrationReader::readMo(BacklogMO &backlog) } backlog.messageid = value(0).toLongLong(); - backlog.time = QDateTime::fromTime_t(value(1).toInt()).toUTC(); + // As of SQLite schema version 31, timestamps are stored in milliseconds instead of + // seconds. This nets us more precision as well as simplifying 64-bit time. + backlog.time = QDateTime::fromMSecsSinceEpoch(value(1).toLongLong()).toUTC(); backlog.bufferid = value(2).toInt(); backlog.type = value(3).toInt(); backlog.flags = value(4).toInt(); @@ -2452,8 +2467,7 @@ bool SqliteMigrationReader::readMo(BacklogMO &backlog) return true; } - -bool SqliteMigrationReader::readMo(IrcServerMO &ircserver) +bool SqliteMigrationReader::readMo(IrcServerMO& ircserver) { if (!next()) return false; @@ -2476,8 +2490,7 @@ bool SqliteMigrationReader::readMo(IrcServerMO &ircserver) return true; } - -bool SqliteMigrationReader::readMo(UserSettingMO &userSetting) +bool SqliteMigrationReader::readMo(UserSettingMO& userSetting) { if (!next()) return false; @@ -2489,8 +2502,7 @@ bool SqliteMigrationReader::readMo(UserSettingMO &userSetting) return true; } - -bool SqliteMigrationReader::readMo(CoreStateMO &coreState) +bool SqliteMigrationReader::readMo(CoreStateMO& coreState) { if (!next()) return false;