X-Git-Url: https://git.quassel-irc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fcore%2Fsqlitestorage.cpp;h=8c2df4b0fb97cdb6e96c336e696a9b484b091652;hb=85087a839d89dc53ed71b41e12244e57f21f67b1;hp=2eae156865caa28021b72f287bb589c91a2b4927;hpb=767e5f04ab1aff5ea98e9d3bf67d8f22043bf90c;p=quassel.git diff --git a/src/core/sqlitestorage.cpp b/src/core/sqlitestorage.cpp index 2eae1568..8c2df4b0 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 * @@ -87,23 +87,40 @@ int SqliteStorage::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) { @@ -123,6 +140,54 @@ bool SqliteStorage::setupSchemaVersion(int version) } +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(); @@ -1914,15 +1979,20 @@ QList SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId QSqlQuery query(db); if (last == -1 && first == -1) { query.prepare(queryString("select_messagesNewestK")); + // Workaround for Qt 4 QSqlQuery::bindValue() not supporting repeated placeholder names + query.bindValue(":bufferidDup1", bufferId.toInt()); } else if (last == -1) { query.prepare(queryString("select_messagesNewerThan")); query.bindValue(":firstmsg", first.toQint64()); + // Workaround for Qt 4 QSqlQuery::bindValue() not supporting repeated placeholder names + query.bindValue(":bufferidDup1", bufferId.toInt()); } else { query.prepare(queryString("select_messagesRange")); query.bindValue(":lastmsg", last.toQint64()); query.bindValue(":firstmsg", first.toQint64()); + // Workaround for Qt 4 QSqlQuery::bindValue() not needed, only has one ":bufferid" } query.bindValue(":bufferid", bufferId.toInt()); query.bindValue(":limit", limit); @@ -1989,15 +2059,20 @@ QList SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId QSqlQuery query(db); if (last == -1 && first == -1) { query.prepare(queryString("select_messagesNewestK_filtered")); + // Workaround for Qt 4 QSqlQuery::bindValue() not supporting repeated placeholder names + query.bindValue(":bufferidDup1", bufferId.toInt()); } else if (last == -1) { query.prepare(queryString("select_messagesNewerThan_filtered")); query.bindValue(":firstmsg", first.toQint64()); + // Workaround for Qt 4 QSqlQuery::bindValue() not supporting repeated placeholder names + query.bindValue(":bufferidDup1", bufferId.toInt()); } else { query.prepare(queryString("select_messagesRange_filtered")); query.bindValue(":lastmsg", last.toQint64()); query.bindValue(":firstmsg", first.toQint64()); + // Workaround for Qt 4 QSqlQuery::bindValue() not needed, only has one ":bufferid" } query.bindValue(":bufferid", bufferId.toInt()); query.bindValue(":limit", limit); @@ -2005,6 +2080,8 @@ QList SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId query.bindValue(":type", typeRaw); int flagsRaw = flags; query.bindValue(":flags", flagsRaw); + // Workaround for Qt 4 QSqlQuery::bindValue() not supporting repeated placeholder names + query.bindValue(":flagsDup1", flagsRaw); safeExec(query); watchQuery(query); @@ -2128,6 +2205,8 @@ QList SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, M query.bindValue(":type", typeRaw); int flagsRaw = flags; query.bindValue(":flags", flagsRaw); + // Workaround for Qt 4 QSqlQuery::bindValue() not supporting repeated placeholder names + query.bindValue(":flagsDup1", flagsRaw); safeExec(query); watchQuery(query); @@ -2193,7 +2272,7 @@ bool SqliteStorage::safeExec(QSqlQuery &query, int retryCount) switch (query.lastError().number()) { case 5: // SQLITE_BUSY 5 /* The database file is locked */ - [[clang::fallthrough]]; + // fallthrough case 6: // SQLITE_LOCKED 6 /* A table in the database is locked */ if (retryCount < _maxRetryCount) return safeExec(query, retryCount + 1);