/***************************************************************************
- * 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 *
#include <QtSql>
-#include "logger.h"
+#include "logmessage.h"
#include "network.h"
#include "quassel.h"
}
-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)
{
}
+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();
{
QSqlQuery logMessageQuery(db);
logMessageQuery.prepare(queryString("insert_message"));
- // Store timestamp in seconds as 64-bit integer
- //
- // NOTE: This is a loss of precision. The database time column would need to store a
- // fractional number to support toMSecsSinceEpoch(), or an upgrade step would need to
- // convert all past times to milliseconds, multiplying by 1000.
-#if QT_VERSION >= 0x050800
- logMessageQuery.bindValue(":time", msg.timestamp().toSecsSinceEpoch());
-#else
- // toSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for now.
- // See https://doc.qt.io/qt-5/qdatetime.html#toMSecsSinceEpoch
- logMessageQuery.bindValue(":time", (qint64)(msg.timestamp().toMSecsSinceEpoch() / 1000));
-#endif
+ // 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());
logMessageQuery.prepare(queryString("insert_message"));
for (int i = 0; i < msgs.count(); i++) {
Message &msg = msgs[i];
- // Store timestamp in seconds as 64-bit integer
- //
- // NOTE: This is a loss of precision. The database time column would need to store a
- // fractional number to support toMSecsSinceEpoch(), or an upgrade step would need to
- // convert all past times to milliseconds, multiplying by 1000.
-#if QT_VERSION >= 0x050800
- logMessageQuery.bindValue(":time", msg.timestamp().toSecsSinceEpoch());
-#else
- // toSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for now.
- // See https://doc.qt.io/qt-5/qdatetime.html#toMSecsSinceEpoch
- logMessageQuery.bindValue(":time",
- (qint64)(msg.timestamp().toMSecsSinceEpoch() / 1000));
-#endif
+ // 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());
while (query.next()) {
Message msg(
- // Read timestamp in seconds as 64-bit integer
- //
- // NOTE: This is a loss of precision. The database time column would need to store
- // a fractional number to support fromMSecsSinceEpoch(), or an upgrade step would
- // need to convert all past times to milliseconds, multiplying by 1000.
-#if QT_VERSION >= 0x050800
- QDateTime::fromSecsSinceEpoch(query.value(1).toLongLong()),
-#else
- // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for
- // now.
- // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
- QDateTime::fromMSecsSinceEpoch((qint64)(query.value(1).toLongLong() * 1000)),
-#endif
+ // 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(),
while (query.next()) {
Message msg(
- // Read timestamp in seconds as 64-bit integer
- //
- // NOTE: This is a loss of precision. The database time column would need
- // to store a fractional number to support fromMSecsSinceEpoch(), or an
- // upgrade step would need to convert all past times to milliseconds,
- // multiplying by 1000.
-#if QT_VERSION >= 0x050800
- QDateTime::fromSecsSinceEpoch(query.value(1).toLongLong()),
-#else
- // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to
- // seconds for now.
- // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
- QDateTime::fromMSecsSinceEpoch(
- (qint64)(query.value(1).toLongLong() * 1000)),
-#endif
+ // 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(),
while (query.next()) {
Message msg(
- // Read timestamp in seconds as 64-bit integer
- //
- // NOTE: This is a loss of precision. The database time column would need to store
- // a fractional number to support fromMSecsSinceEpoch(), or an upgrade step would
- // need to convert all past times to milliseconds, multiplying by 1000.
-#if QT_VERSION >= 0x050800
- QDateTime::fromSecsSinceEpoch(query.value(2).toLongLong()),
-#else
- // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for
- // now.
- // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
- QDateTime::fromMSecsSinceEpoch((qint64)(query.value(2).toLongLong() * 1000)),
-#endif
+ // 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(),
while (query.next()) {
Message msg(
- // Read timestamp in seconds as 64-bit integer
- //
- // NOTE: This is a loss of precision. The database time column would need
- // to store a fractional number to support fromMSecsSinceEpoch(), or an
- // upgrade step would need to convert all past times to milliseconds,
- // multiplying by 1000.
-#if QT_VERSION >= 0x050800
- QDateTime::fromSecsSinceEpoch(query.value(2).toLongLong()),
-#else
- // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to
- // seconds for now.
- // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
- QDateTime::fromMSecsSinceEpoch(
- (qint64)(query.value(2).toLongLong() * 1000)),
-#endif
+ // 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(),
}
-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";
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);
}
backlog.messageid = value(0).toLongLong();
- // Read timestamp in seconds as 64-bit integer
- //
- // NOTE: This is a loss of precision. The database time column would need to store a
- // fractional number to support fromMSecsSinceEpoch(), or an upgrade step would need to convert
- // all past times to milliseconds, multiplying by 1000.
-#if QT_VERSION >= 0x050800
- backlog.time = QDateTime::fromSecsSinceEpoch(value(1).toLongLong()).toUTC();
-#else
- // fromSecsSinceEpoch() was added in Qt 5.8. Manually downconvert to seconds for
- // now.
- // See https://doc.qt.io/qt-5/qdatetime.html#fromMSecsSinceEpoch
- backlog.time = QDateTime::fromMSecsSinceEpoch((qint64)(value(1).toLongLong() * 1000)
- ).toUTC();
-#endif
+ // 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();