Cleanup allowing for tags to be available at later points, adds TAGMSG
[quassel.git] / src / core / postgresqlstorage.cpp
index 200fd14..40ff80c 100644 (file)
@@ -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,7 +22,6 @@
 
 #include <QtSql>
 
-#include "logmessage.h"
 #include "network.h"
 #include "quassel.h"
 
@@ -46,7 +45,7 @@ std::unique_ptr<AbstractSqlMigrationWriter> PostgreSqlStorage::createMigrationWr
 bool PostgreSqlStorage::isAvailable() const
 {
     if (!QSqlDatabase::isDriverAvailable("QPSQL")) {
-        quWarning() << qPrintable(tr("PostgreSQL driver plugin not available for Qt. Installed drivers:"))
+        qWarning() << qPrintable(tr("PostgreSQL driver plugin not available for Qt. Installed drivers:"))
                     << qPrintable(QSqlDatabase::drivers().join(", "));
         return false;
     }
@@ -92,7 +91,7 @@ bool PostgreSqlStorage::initDbSession(QSqlDatabase& db)
         // as this is the expected behavior.
         // If it is a newer version, switch to legacy mode.
 
-        quWarning() << "Switching Postgres to legacy mode. (set standard conforming strings to off)";
+        qWarning() << "Switching Postgres to legacy mode. (set standard conforming strings to off)";
         // If the following calls fail, it is a legacy DB anyways, so it doesn't matter
         // and no need to check the outcome.
         db.exec("set standard_conforming_strings = off");
@@ -106,14 +105,14 @@ bool PostgreSqlStorage::initDbSession(QSqlDatabase& db)
             if (query.lastError().isValid()) {
                 // We cannot enable standard conforming strings...
                 // since Quassel does no escaping by itself, this would yield a major vulnerability.
-                quError() << "Failed to enable standard_conforming_strings for the Postgres db!";
+                qCritical() << "Failed to enable standard_conforming_strings for the Postgres db!";
                 return false;
             }
         }
         break;
     default:
         // The slash got replaced with 0 or more than 2 slashes! o_O
-        quError() << "Your version of Qt does something _VERY_ strange to slashes in QSqlQueries! You should consult your trusted doctor!";
+        qCritical() << "Your version of Qt does something _VERY_ strange to slashes in QSqlQueries! You should consult your trusted doctor!";
         return false;
         break;
     }
@@ -121,7 +120,7 @@ bool PostgreSqlStorage::initDbSession(QSqlDatabase& db)
     // Set the PostgreSQL session timezone to UTC, since we want timestamps stored in UTC
     QSqlQuery tzQuery = db.exec("SET timezone = 'UTC'");
     if (tzQuery.lastError().isValid()) {
-        quError() << "Failed to set timezone to UTC!";
+        qCritical() << "Failed to set timezone to UTC!";
         return false;
     }
 
@@ -165,19 +164,39 @@ int PostgreSqlStorage::installedSchemaVersion()
     return AbstractSqlStorage::installedSchemaVersion();
 }
 
-bool PostgreSqlStorage::updateSchemaVersion(int newVersion)
+bool PostgreSqlStorage::updateSchemaVersion(int newVersion, bool clearUpgradeStep)
 {
-    QSqlQuery query(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.
+    QSqlDatabase db = logDb();
+    if (!beginTransaction(db)) {
+        qWarning() << "PostgreSqlStorage::updateSchemaVersion(int, bool): cannot start transaction!";
+        qWarning() << " -" << qPrintable(db.lastError().text());
+        return false;
+    }
+
+    QSqlQuery query(db);
     query.prepare("UPDATE coreinfo SET value = :version WHERE key = 'schemaversion'");
     query.bindValue(":version", newVersion);
     safeExec(query);
 
-    bool success = true;
     if (!watchQuery(query)) {
-        qCritical() << "PostgreSqlStorage::updateSchemaVersion(int): Updating schema version failed!";
-        success = false;
+        qCritical() << "PostgreSqlStorage::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 PostgreSqlStorage::setupSchemaVersion(int version)
@@ -195,6 +214,50 @@ bool PostgreSqlStorage::setupSchemaVersion(int version)
     return success;
 }
 
+QString PostgreSqlStorage::schemaVersionUpgradeStep()
+{
+    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 PostgreSqlStorage::setSchemaVersionUpgradeStep(QString upgradeQuery)
+{
+    // 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);
+
+    // Make sure that the query didn't fail (shouldn't ever happen), and that some non-zero number
+    // of rows were affected
+    bool success = watchQuery(query) && 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 PostgreSqlStorage::addUser(const QString& user, const QString& password, const QString& authenticator)
 {
     QSqlQuery query(logDb());