/***************************************************************************
- * Copyright (C) 2005-2015 by the Quassel Project *
+ * Copyright (C) 2005-2018 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 "network.h"
#include "quassel.h"
-PostgreSqlStorage::PostgreSqlStorage(QObject *parent)
- : AbstractSqlStorage(parent),
- _port(-1)
-{
-}
-
+PostgreSqlStorage::PostgreSqlStorage(QObject* parent)
+ : AbstractSqlStorage(parent)
+{}
-PostgreSqlStorage::~PostgreSqlStorage()
+std::unique_ptr<AbstractSqlMigrationWriter> PostgreSqlStorage::createMigrationWriter()
{
-}
-
-
-AbstractSqlMigrationWriter *PostgreSqlStorage::createMigrationWriter()
-{
- PostgreSqlMigrationWriter *writer = new PostgreSqlMigrationWriter();
+ auto writer = new PostgreSqlMigrationWriter();
QVariantMap properties;
properties["Username"] = _userName;
properties["Password"] = _password;
properties["Hostname"] = _hostName;
properties["Port"] = _port;
properties["Database"] = _databaseName;
- writer->setConnectionProperties(properties);
- return writer;
+ writer->setConnectionProperties(properties, {}, false);
+ return std::unique_ptr<AbstractSqlMigrationWriter>{writer};
}
-
bool PostgreSqlStorage::isAvailable() const
{
- qDebug() << QSqlDatabase::drivers();
- if (!QSqlDatabase::isDriverAvailable("QPSQL")) return false;
+ if (!QSqlDatabase::isDriverAvailable("QPSQL")) {
+ qWarning() << qPrintable(tr("PostgreSQL driver plugin not available for Qt. Installed drivers:"))
+ << qPrintable(QSqlDatabase::drivers().join(", "));
+ return false;
+ }
return true;
}
-
-QString PostgreSqlStorage::displayName() const
+QString PostgreSqlStorage::backendId() const
{
return QString("PostgreSQL");
}
+QString PostgreSqlStorage::displayName() const
+{
+ return backendId(); // Note: Pre-0.13 clients use the displayName property for backend idenfication
+}
QString PostgreSqlStorage::description() const
{
return tr("PostgreSQL Turbo Bomber HD!");
}
-
-QStringList PostgreSqlStorage::setupKeys() const
+QVariantList PostgreSqlStorage::setupData() const
{
- QStringList keys;
- keys << "Username"
- << "Password"
- << "Hostname"
- << "Port"
- << "Database";
- return keys;
+ QVariantList data;
+ data << "Username" << tr("Username") << QString("quassel") << "Password" << tr("Password") << QString() << "Hostname" << tr("Hostname")
+ << QString("localhost") << "Port" << tr("Port") << 5432 << "Database" << tr("Database") << QString("quassel");
+ return data;
}
-
-QVariantMap PostgreSqlStorage::setupDefaults() const
-{
- QVariantMap map;
- map["Username"] = QVariant(QString("quassel"));
- map["Hostname"] = QVariant(QString("localhost"));
- map["Port"] = QVariant(5432);
- map["Database"] = QVariant(QString("quassel"));
- return map;
-}
-
-
-bool PostgreSqlStorage::initDbSession(QSqlDatabase &db)
+bool PostgreSqlStorage::initDbSession(QSqlDatabase& db)
{
// check whether the Qt driver performs string escaping or not.
// i.e. test if it doubles slashes.
testField.setType(QVariant::String);
testField.setValue("\\");
QString formattedString = db.driver()->formatValue(testField);
- switch(formattedString.count('\\')) {
+ switch (formattedString.count('\\')) {
case 2:
// yes it does... and we cannot do anything to change the behavior of Qt.
// If this is a legacy DB (Postgres < 8.2), then everything is already ok,
// 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");
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;
}
// 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;
}
return true;
}
-
-void PostgreSqlStorage::setConnectionProperties(const QVariantMap &properties)
+void PostgreSqlStorage::setConnectionProperties(const QVariantMap& properties, const QProcessEnvironment& environment, bool loadFromEnvironment)
{
- _userName = properties["Username"].toString();
- _password = properties["Password"].toString();
- _hostName = properties["Hostname"].toString();
- _port = properties["Port"].toInt();
- _databaseName = properties["Database"].toString();
+ if (loadFromEnvironment) {
+ _userName = environment.value("DB_PGSQL_USERNAME");
+ _password = environment.value("DB_PGSQL_PASSWORD");
+ _hostName = environment.value("DB_PGSQL_HOSTNAME");
+ _port = environment.value("DB_PGSQL_PORT").toInt();
+ _databaseName = environment.value("DB_PGSQL_DATABASE");
+ }
+ else {
+ _userName = properties["Username"].toString();
+ _password = properties["Password"].toString();
+ _hostName = properties["Hostname"].toString();
+ _port = properties["Port"].toInt();
+ _databaseName = properties["Database"].toString();
+ }
}
-
int PostgreSqlStorage::installedSchemaVersion()
{
QSqlQuery query(logDb());
return AbstractSqlStorage::installedSchemaVersion();
}
-
bool PostgreSqlStorage::updateSchemaVersion(int newVersion)
{
QSqlQuery query(logDb());
return success;
}
-
bool PostgreSqlStorage::setupSchemaVersion(int version)
{
QSqlQuery query(logDb());
return success;
}
-
-UserId PostgreSqlStorage::addUser(const QString &user, const QString &password)
+UserId PostgreSqlStorage::addUser(const QString& user, const QString& password, const QString& authenticator)
{
QSqlQuery query(logDb());
query.prepare(queryString("insert_quasseluser"));
query.bindValue(":username", user);
query.bindValue(":password", hashPassword(password));
query.bindValue(":hashversion", Storage::HashVersion::Latest);
+ query.bindValue(":authenticator", authenticator);
safeExec(query);
if (!watchQuery(query))
return 0;
return uid;
}
-
-bool PostgreSqlStorage::updateUser(UserId user, const QString &password)
+bool PostgreSqlStorage::updateUser(UserId user, const QString& password)
{
QSqlQuery query(logDb());
query.prepare(queryString("update_userpassword"));
return query.numRowsAffected() != 0;
}
-
-void PostgreSqlStorage::renameUser(UserId user, const QString &newName)
+void PostgreSqlStorage::renameUser(UserId user, const QString& newName)
{
QSqlQuery query(logDb());
query.prepare(queryString("update_username"));
emit userRenamed(user, newName);
}
-
-UserId PostgreSqlStorage::validateUser(const QString &user, const QString &password)
+UserId PostgreSqlStorage::validateUser(const QString& user, const QString& password)
{
QSqlQuery query(logDb());
query.prepare(queryString("select_authuser"));
safeExec(query);
watchQuery(query);
- if (query.first() && checkHashedPassword(query.value(0).toInt(), password, query.value(1).toString(), static_cast<Storage::HashVersion>(query.value(2).toInt()))) {
+ if (query.first()
+ && checkHashedPassword(query.value(0).toInt(),
+ password,
+ query.value(1).toString(),
+ static_cast<Storage::HashVersion>(query.value(2).toInt()))) {
return query.value(0).toInt();
}
else {
}
}
-
-UserId PostgreSqlStorage::getUserId(const QString &user)
+UserId PostgreSqlStorage::getUserId(const QString& user)
{
QSqlQuery query(logDb());
query.prepare(queryString("select_userid"));
}
}
+QString PostgreSqlStorage::getUserAuthenticator(const UserId userid)
+{
+ QSqlQuery query(logDb());
+ query.prepare(queryString("select_authenticator"));
+ query.bindValue(":userid", userid.toInt());
+ safeExec(query);
+ watchQuery(query);
+
+ if (query.first()) {
+ return query.value(0).toString();
+ }
+ else {
+ return QString("");
+ }
+}
UserId PostgreSqlStorage::internalUser()
{
}
}
-
void PostgreSqlStorage::delUser(UserId user)
{
QSqlDatabase db = logDb();
}
}
-
-void PostgreSqlStorage::setUserSetting(UserId userId, const QString &settingName, const QVariant &data)
+void PostgreSqlStorage::setUserSetting(UserId userId, const QString& settingName, const QVariant& data)
{
QByteArray rawData;
QDataStream out(&rawData, QIODevice::WriteOnly);
watchQuery(setQuery);
}
-
-QVariant PostgreSqlStorage::getUserSetting(UserId userId, const QString &settingName, const QVariant &defaultData)
+QVariant PostgreSqlStorage::getUserSetting(UserId userId, const QString& settingName, const QVariant& defaultData)
{
QSqlQuery query(logDb());
query.prepare(queryString("select_user_setting"));
}
}
+void PostgreSqlStorage::setCoreState(const QVariantList& data)
+{
+ QByteArray rawData;
+ QDataStream out(&rawData, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_2);
+ out << data;
+
+ QSqlDatabase db = logDb();
+ QSqlQuery selectQuery(db);
+ selectQuery.prepare(queryString("select_core_state"));
+ selectQuery.bindValue(":key", "active_sessions");
+ safeExec(selectQuery);
+ watchQuery(selectQuery);
+
+ QString setQueryString;
+ if (!selectQuery.first()) {
+ setQueryString = queryString("insert_core_state");
+ }
+ else {
+ setQueryString = queryString("update_core_state");
+ }
-IdentityId PostgreSqlStorage::createIdentity(UserId user, CoreIdentity &identity)
+ QSqlQuery setQuery(db);
+ setQuery.prepare(setQueryString);
+ setQuery.bindValue(":key", "active_sessions");
+ setQuery.bindValue(":value", rawData);
+ safeExec(setQuery);
+ watchQuery(setQuery);
+}
+
+QVariantList PostgreSqlStorage::getCoreState(const QVariantList& defaultData)
+{
+ QSqlQuery query(logDb());
+ query.prepare(queryString("select_core_state"));
+ query.bindValue(":key", "active_sessions");
+ safeExec(query);
+ watchQuery(query);
+
+ if (query.first()) {
+ QVariantList data;
+ QByteArray rawData = query.value(0).toByteArray();
+ QDataStream in(&rawData, QIODevice::ReadOnly);
+ in.setVersion(QDataStream::Qt_4_2);
+ in >> data;
+ return data;
+ }
+ else {
+ return defaultData;
+ }
+}
+
+IdentityId PostgreSqlStorage::createIdentity(UserId user, CoreIdentity& identity)
{
IdentityId identityId;
safeExec(query);
if (!watchQuery(query)) {
db.rollback();
- return IdentityId();
+ return {};
}
query.first();
if (!identityId.isValid()) {
db.rollback();
- return IdentityId();
+ return {};
}
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);
if (!watchQuery(insertNickQuery)) {
db.rollback();
- return IdentityId();
+ return {};
}
}
if (!db.commit()) {
qWarning() << "PostgreSqlStorage::createIdentity(): committing data failed!";
qWarning() << " -" << qPrintable(db.lastError().text());
- return IdentityId();
+ return {};
}
return identityId;
}
-
-bool PostgreSqlStorage::updateIdentity(UserId user, const CoreIdentity &identity)
+bool PostgreSqlStorage::updateIdentity(UserId user, const CoreIdentity& identity)
{
QSqlDatabase db = logDb();
if (!beginTransaction(db)) {
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);
return true;
}
-
void PostgreSqlStorage::removeIdentity(UserId user, IdentityId identityId)
{
QSqlDatabase db = logDb();
}
}
-
QList<CoreIdentity> PostgreSqlStorage::identities(UserId user)
{
QList<CoreIdentity> identities;
return identities;
}
-
-NetworkId PostgreSqlStorage::createNetwork(UserId user, const NetworkInfo &info)
+NetworkId PostgreSqlStorage::createNetwork(UserId user, const NetworkInfo& info)
{
NetworkId networkId;
safeExec(query);
if (!watchQuery(query)) {
db.rollback();
- return NetworkId();
+ return {};
}
query.first();
if (!networkId.isValid()) {
db.rollback();
- 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);
safeExec(insertServersQuery);
if (!watchQuery(insertServersQuery)) {
db.rollback();
- return NetworkId();
+ return {};
}
}
if (!db.commit()) {
qWarning() << "PostgreSqlStorage::createNetwork(): committing data failed!";
qWarning() << " -" << qPrintable(db.lastError().text());
- return NetworkId();
+ return {};
}
return networkId;
}
-
-void PostgreSqlStorage::bindNetworkInfo(QSqlQuery &query, const NetworkInfo &info)
+void PostgreSqlStorage::bindNetworkInfo(QSqlQuery& query, const NetworkInfo& info)
{
query.bindValue(":networkname", info.networkName);
query.bindValue(":identityid", info.identity.isValid() ? info.identity.toInt() : QVariant());
query.bindValue(":autoreconnectretries", info.autoReconnectRetries);
query.bindValue(":unlimitedconnectretries", info.unlimitedReconnectRetries);
query.bindValue(":rejoinchannels", info.rejoinChannels);
+ // Custom rate limiting
+ query.bindValue(":usecustomessagerate", info.useCustomMessageRate);
+ query.bindValue(":messagerateburstsize", info.messageRateBurstSize);
+ query.bindValue(":messageratedelay", info.messageRateDelay);
+ query.bindValue(":unlimitedmessagerate", info.unlimitedMessageRate);
if (info.networkId.isValid())
query.bindValue(":networkid", info.networkId.toInt());
}
-
-void PostgreSqlStorage::bindServerInfo(QSqlQuery &query, const Network::Server &server)
+void PostgreSqlStorage::bindServerInfo(QSqlQuery& query, const Network::Server& server)
{
query.bindValue(":hostname", server.host);
query.bindValue(":port", server.port);
query.bindValue(":proxyport", server.proxyPort);
query.bindValue(":proxyuser", server.proxyUser);
query.bindValue(":proxypass", server.proxyPass);
+ query.bindValue(":sslverify", server.sslVerify);
}
-
-bool PostgreSqlStorage::updateNetwork(UserId user, const NetworkInfo &info)
+bool PostgreSqlStorage::updateNetwork(UserId user, const NetworkInfo& info)
{
QSqlDatabase db = logDb();
if (!beginTransaction(db)) {
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);
return true;
}
-
-bool PostgreSqlStorage::removeNetwork(UserId user, const NetworkId &networkId)
+bool PostgreSqlStorage::removeNetwork(UserId user, const NetworkId& networkId)
{
QSqlDatabase db = logDb();
if (!beginTransaction(db)) {
return true;
}
-
QList<NetworkInfo> PostgreSqlStorage::networks(UserId user)
{
QList<NetworkInfo> nets;
net.useSasl = networksQuery.value(16).toBool();
net.saslAccount = networksQuery.value(17).toString();
net.saslPassword = networksQuery.value(18).toString();
+ // Custom rate limiting
+ net.useCustomMessageRate = networksQuery.value(19).toBool();
+ net.messageRateBurstSize = networksQuery.value(20).toUInt();
+ net.messageRateDelay = networksQuery.value(21).toUInt();
+ net.unlimitedMessageRate = networksQuery.value(22).toBool();
serversQuery.bindValue(":networkid", net.networkId.toInt());
safeExec(serversQuery);
server.proxyPort = serversQuery.value(8).toUInt();
server.proxyUser = serversQuery.value(9).toString();
server.proxyPass = serversQuery.value(10).toString();
+ server.sslVerify = serversQuery.value(11).toBool();
servers << server;
}
net.serverList = servers;
return nets;
}
-
QList<NetworkId> PostgreSqlStorage::connectedNetworks(UserId user)
{
QList<NetworkId> connectedNets;
return connectedNets;
}
-
-void PostgreSqlStorage::setNetworkConnected(UserId user, const NetworkId &networkId, bool isConnected)
+void PostgreSqlStorage::setNetworkConnected(UserId user, const NetworkId& networkId, bool isConnected)
{
QSqlQuery query(logDb());
query.prepare(queryString("update_network_connected"));
watchQuery(query);
}
-
-QHash<QString, QString> PostgreSqlStorage::persistentChannels(UserId user, const NetworkId &networkId)
+QHash<QString, QString> PostgreSqlStorage::persistentChannels(UserId user, const NetworkId& networkId)
{
QHash<QString, QString> persistentChans;
return persistentChans;
}
-
-void PostgreSqlStorage::setChannelPersistent(UserId user, const NetworkId &networkId, const QString &channel, bool isJoined)
+void PostgreSqlStorage::setChannelPersistent(UserId user, const NetworkId& networkId, const QString& channel, bool isJoined)
{
QSqlQuery query(logDb());
query.prepare(queryString("update_buffer_persistent_channel"));
query.bindValue(":userid", user.toInt());
- query.bindValue(":networkId", networkId.toInt());
+ query.bindValue(":networkid", networkId.toInt());
query.bindValue(":buffercname", channel.toLower());
query.bindValue(":joined", isJoined);
safeExec(query);
watchQuery(query);
}
-
-void PostgreSqlStorage::setPersistentChannelKey(UserId user, const NetworkId &networkId, const QString &channel, const QString &key)
+void PostgreSqlStorage::setPersistentChannelKey(UserId user, const NetworkId& networkId, const QString& channel, const QString& key)
{
QSqlQuery query(logDb());
query.prepare(queryString("update_buffer_set_channel_key"));
query.bindValue(":userid", user.toInt());
- query.bindValue(":networkId", networkId.toInt());
+ query.bindValue(":networkid", networkId.toInt());
query.bindValue(":buffercname", channel.toLower());
query.bindValue(":key", key);
safeExec(query);
watchQuery(query);
}
-
QString PostgreSqlStorage::awayMessage(UserId user, NetworkId networkId)
{
QSqlQuery query(logDb());
return awayMsg;
}
-
-void PostgreSqlStorage::setAwayMessage(UserId user, NetworkId networkId, const QString &awayMsg)
+void PostgreSqlStorage::setAwayMessage(UserId user, NetworkId networkId, const QString& awayMsg)
{
QSqlQuery query(logDb());
query.prepare(queryString("update_network_set_awaymsg"));
watchQuery(query);
}
-
QString PostgreSqlStorage::userModes(UserId user, NetworkId networkId)
{
QSqlQuery query(logDb());
return modes;
}
-
-void PostgreSqlStorage::setUserModes(UserId user, NetworkId networkId, const QString &userModes)
+void PostgreSqlStorage::setUserModes(UserId user, NetworkId networkId, const QString& userModes)
{
QSqlQuery query(logDb());
query.prepare(queryString("update_network_set_usermode"));
watchQuery(query);
}
-
-BufferInfo PostgreSqlStorage::bufferInfo(UserId user, const NetworkId &networkId, BufferInfo::Type type, const QString &buffer, bool create)
+BufferInfo PostgreSqlStorage::bufferInfo(UserId user, const NetworkId& networkId, BufferInfo::Type type, const QString& buffer, bool create)
{
QSqlDatabase db = logDb();
if (!beginTransaction(db)) {
qWarning() << "PostgreSqlStorage::bufferInfo(): cannot start read only transaction!";
qWarning() << " -" << qPrintable(db.lastError().text());
- return BufferInfo();
+ return {};
}
QSqlQuery query(db);
if (!create) {
db.rollback();
- return BufferInfo();
+ return {};
}
QSqlQuery createQuery(db);
return bufferInfo;
}
-
-BufferInfo PostgreSqlStorage::getBufferInfo(UserId user, const BufferId &bufferId)
+BufferInfo PostgreSqlStorage::getBufferInfo(UserId user, const BufferId& bufferId)
{
QSqlQuery query(logDb());
query.prepare(queryString("select_buffer_by_id"));
query.bindValue(":bufferid", bufferId.toInt());
safeExec(query);
if (!watchQuery(query))
- return BufferInfo();
+ return {};
if (!query.first())
- return BufferInfo();
+ return {};
- 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());
return bufferInfo;
}
-
QList<BufferInfo> PostgreSqlStorage::requestBuffers(UserId user)
{
QList<BufferInfo> bufferlist;
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();
return bufferlist;
}
-
QList<BufferId> PostgreSqlStorage::requestBufferIdsForNetwork(UserId user, NetworkId networkId)
{
QList<BufferId> bufferList;
return bufferList;
}
-
-bool PostgreSqlStorage::removeBuffer(const UserId &user, const BufferId &bufferId)
+bool PostgreSqlStorage::removeBuffer(const UserId& user, const BufferId& bufferId)
{
QSqlDatabase db = logDb();
if (!beginTransaction(db)) {
return true;
default:
// there was more then one buffer deleted...
- qWarning() << "PostgreSqlStorage::removeBuffer(): Userid" << user << "BufferId" << "caused deletion of" << numRows << "Buffers! Rolling back transaction...";
+ qWarning() << "PostgreSqlStorage::removeBuffer(): Userid" << user << "BufferId"
+ << "caused deletion of" << numRows << "Buffers! Rolling back transaction...";
db.rollback();
return false;
}
}
-
-bool PostgreSqlStorage::renameBuffer(const UserId &user, const BufferId &bufferId, const QString &newName)
+bool PostgreSqlStorage::renameBuffer(const UserId& user, const BufferId& bufferId, const QString& newName)
{
QSqlDatabase db = logDb();
if (!beginTransaction(db)) {
return true;
default:
// there was more then one buffer deleted...
- qWarning() << "PostgreSqlStorage::renameBuffer(): Userid" << user << "BufferId" << "affected" << numRows << "Buffers! Rolling back transaction...";
+ qWarning() << "PostgreSqlStorage::renameBuffer(): Userid" << user << "BufferId"
+ << "affected" << numRows << "Buffers! Rolling back transaction...";
db.rollback();
return false;
}
}
-
-bool PostgreSqlStorage::mergeBuffersPermanently(const UserId &user, const BufferId &bufferId1, const BufferId &bufferId2)
+bool PostgreSqlStorage::mergeBuffersPermanently(const UserId& user, const BufferId& bufferId1, const BufferId& bufferId2)
{
QSqlDatabase db = logDb();
if (!beginTransaction(db)) {
return true;
}
-
-void PostgreSqlStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId, const MsgId &msgId)
+void PostgreSqlStorage::setBufferLastSeenMsg(UserId user, const BufferId& bufferId, const MsgId& msgId)
{
QSqlQuery query(logDb());
query.prepare(queryString("update_buffer_lastseen"));
query.bindValue(":userid", user.toInt());
query.bindValue(":bufferid", bufferId.toInt());
- query.bindValue(":lastseenmsgid", msgId.toInt());
+ query.bindValue(":lastseenmsgid", msgId.toQint64());
safeExec(query);
watchQuery(query);
}
-
QHash<BufferId, MsgId> PostgreSqlStorage::bufferLastSeenMsgIds(UserId user)
{
QHash<BufferId, MsgId> lastSeenHash;
}
while (query.next()) {
- lastSeenHash[query.value(0).toInt()] = query.value(1).toInt();
+ lastSeenHash[query.value(0).toInt()] = query.value(1).toLongLong();
}
db.commit();
return lastSeenHash;
}
-
-void PostgreSqlStorage::setBufferMarkerLineMsg(UserId user, const BufferId &bufferId, const MsgId &msgId)
+void PostgreSqlStorage::setBufferMarkerLineMsg(UserId user, const BufferId& bufferId, const MsgId& msgId)
{
QSqlQuery query(logDb());
query.prepare(queryString("update_buffer_markerlinemsgid"));
query.bindValue(":userid", user.toInt());
query.bindValue(":bufferid", bufferId.toInt());
- query.bindValue(":markerlinemsgid", msgId.toInt());
+ query.bindValue(":markerlinemsgid", msgId.toQint64());
safeExec(query);
watchQuery(query);
}
-
QHash<BufferId, MsgId> PostgreSqlStorage::bufferMarkerLineMsgIds(UserId user)
{
QHash<BufferId, MsgId> markerLineHash;
}
while (query.next()) {
- markerLineHash[query.value(0).toInt()] = query.value(1).toInt();
+ markerLineHash[query.value(0).toInt()] = query.value(1).toLongLong();
}
db.commit();
return markerLineHash;
}
+void PostgreSqlStorage::setBufferActivity(UserId user, BufferId bufferId, Message::Types bufferActivity)
+{
+ QSqlQuery query(logDb());
+ query.prepare(queryString("update_buffer_bufferactivity"));
+
+ query.bindValue(":userid", user.toInt());
+ query.bindValue(":bufferid", bufferId.toInt());
+ query.bindValue(":bufferactivity", (int)bufferActivity);
+ safeExec(query);
+ watchQuery(query);
+}
+
+QHash<BufferId, Message::Types> PostgreSqlStorage::bufferActivities(UserId user)
+{
+ QHash<BufferId, Message::Types> bufferActivityHash;
+
+ QSqlDatabase db = logDb();
+ if (!beginReadOnlyTransaction(db)) {
+ qWarning() << "PostgreSqlStorage::bufferActivities(): cannot start read only transaction!";
+ qWarning() << " -" << qPrintable(db.lastError().text());
+ return bufferActivityHash;
+ }
+
+ QSqlQuery query(db);
+ query.prepare(queryString("select_buffer_bufferactivities"));
+ query.bindValue(":userid", user.toInt());
+ safeExec(query);
+ if (!watchQuery(query)) {
+ db.rollback();
+ return bufferActivityHash;
+ }
+
+ while (query.next()) {
+ bufferActivityHash[query.value(0).toInt()] = Message::Types(query.value(1).toInt());
+ }
+
+ db.commit();
+ return bufferActivityHash;
+}
+
+Message::Types PostgreSqlStorage::bufferActivity(BufferId bufferId, MsgId lastSeenMsgId)
+{
+ QSqlQuery query(logDb());
+ query.prepare(queryString("select_buffer_bufferactivity"));
+ query.bindValue(":bufferid", bufferId.toInt());
+ query.bindValue(":lastseenmsgid", lastSeenMsgId.toQint64());
+ safeExec(query);
+ watchQuery(query);
+ Message::Types result = Message::Types(nullptr);
+ if (query.first())
+ result = Message::Types(query.value(0).toInt());
+ return result;
+}
-bool PostgreSqlStorage::logMessage(Message &msg)
+QHash<QString, QByteArray> PostgreSqlStorage::bufferCiphers(UserId user, const NetworkId& networkId)
+{
+ QHash<QString, QByteArray> bufferCiphers;
+
+ QSqlDatabase db = logDb();
+ if (!beginReadOnlyTransaction(db)) {
+ qWarning() << "PostgreSqlStorage::persistentChannels(): cannot start read only transaction!";
+ qWarning() << " -" << qPrintable(db.lastError().text());
+ return bufferCiphers;
+ }
+
+ QSqlQuery query(db);
+ query.prepare(queryString("select_buffer_ciphers"));
+ query.bindValue(":userid", user.toInt());
+ query.bindValue(":networkid", networkId.toInt());
+ safeExec(query);
+ watchQuery(query);
+
+ while (query.next()) {
+ bufferCiphers[query.value(0).toString()] = QByteArray::fromHex(query.value(1).toString().toUtf8());
+ }
+
+ db.commit();
+ return bufferCiphers;
+}
+
+void PostgreSqlStorage::setBufferCipher(UserId user, const NetworkId& networkId, const QString& bufferName, const QByteArray& cipher)
+{
+ QSqlQuery query(logDb());
+ query.prepare(queryString("update_buffer_cipher"));
+ query.bindValue(":userid", user.toInt());
+ query.bindValue(":networkid", networkId.toInt());
+ query.bindValue(":buffercname", bufferName.toLower());
+ query.bindValue(":cipher", QString(cipher.toHex()));
+ safeExec(query);
+ watchQuery(query);
+}
+
+void PostgreSqlStorage::setHighlightCount(UserId user, BufferId bufferId, int highlightcount)
+{
+ QSqlQuery query(logDb());
+ query.prepare(queryString("update_buffer_highlightcount"));
+
+ query.bindValue(":userid", user.toInt());
+ query.bindValue(":bufferid", bufferId.toInt());
+ query.bindValue(":highlightcount", highlightcount);
+ safeExec(query);
+ watchQuery(query);
+}
+
+QHash<BufferId, int> PostgreSqlStorage::highlightCounts(UserId user)
+{
+ QHash<BufferId, int> highlightCountHash;
+
+ QSqlDatabase db = logDb();
+ if (!beginReadOnlyTransaction(db)) {
+ qWarning() << "PostgreSqlStorage::highlightCounts(): cannot start read only transaction!";
+ qWarning() << " -" << qPrintable(db.lastError().text());
+ return highlightCountHash;
+ }
+
+ QSqlQuery query(db);
+ query.prepare(queryString("select_buffer_highlightcounts"));
+ query.bindValue(":userid", user.toInt());
+ safeExec(query);
+ if (!watchQuery(query)) {
+ db.rollback();
+ return highlightCountHash;
+ }
+
+ while (query.next()) {
+ highlightCountHash[query.value(0).toInt()] = query.value(1).toInt();
+ }
+
+ db.commit();
+ return highlightCountHash;
+}
+
+int PostgreSqlStorage::highlightCount(BufferId bufferId, MsgId lastSeenMsgId)
+{
+ QSqlQuery query(logDb());
+ query.prepare(queryString("select_buffer_highlightcount"));
+ query.bindValue(":bufferid", bufferId.toInt());
+ query.bindValue(":lastseenmsgid", lastSeenMsgId.toQint64());
+ safeExec(query);
+ watchQuery(query);
+ auto result = int(0);
+ if (query.first())
+ result = query.value(0).toInt();
+ return result;
+}
+
+bool PostgreSqlStorage::logMessage(Message& msg)
{
QSqlDatabase db = logDb();
if (!beginTransaction(db)) {
return false;
}
- QSqlQuery getSenderIdQuery = executePreparedQuery("select_senderid", msg.sender(), db);
- int senderId;
+ QVariantList senderParams;
+ senderParams << msg.sender() << msg.realName() << msg.avatarUrl();
+ QSqlQuery getSenderIdQuery = executePreparedQuery("select_senderid", senderParams, db);
+ qint64 senderId;
if (getSenderIdQuery.first()) {
- senderId = getSenderIdQuery.value(0).toInt();
+ senderId = getSenderIdQuery.value(0).toLongLong();
}
else {
// it's possible that the sender was already added by another thread
// since the insert might fail we're setting a savepoint
savePoint("sender_sp1", db);
- QSqlQuery addSenderQuery = executePreparedQuery("insert_sender", msg.sender(), db);
+ QSqlQuery addSenderQuery = executePreparedQuery("insert_sender", senderParams, db);
if (addSenderQuery.lastError().isValid()) {
rollbackSavePoint("sender_sp1", db);
- getSenderIdQuery = executePreparedQuery("select_senderid", msg.sender(), db);
+ getSenderIdQuery = executePreparedQuery("select_senderid", senderParams, db);
watchQuery(getSenderIdQuery);
getSenderIdQuery.first();
- senderId = getSenderIdQuery.value(0).toInt();
+ senderId = getSenderIdQuery.value(0).toLongLong();
}
else {
releaseSavePoint("sender_sp1", db);
addSenderQuery.first();
- senderId = addSenderQuery.value(0).toInt();
+ senderId = addSenderQuery.value(0).toLongLong();
}
}
QVariantList params;
- params << msg.timestamp()
- << msg.bufferInfo().bufferId().toInt()
- << msg.type()
- << (int)msg.flags()
- << senderId
+ // PostgreSQL handles QDateTime()'s serialized format by default, and QDateTime() serializes
+ // to a 64-bit time compatible format by default.
+ params << msg.timestamp() << msg.bufferInfo().bufferId().toInt() << msg.type() << (int)msg.flags() << senderId << msg.senderPrefixes()
<< msg.contents();
QSqlQuery logMessageQuery = executePreparedQuery("insert_message", params, db);
}
logMessageQuery.first();
- MsgId msgId = logMessageQuery.value(0).toInt();
+ MsgId msgId = logMessageQuery.value(0).toLongLong();
db.commit();
if (msgId.isValid()) {
msg.setMsgId(msgId);
}
}
-
-bool PostgreSqlStorage::logMessages(MessageList &msgs)
+bool PostgreSqlStorage::logMessages(MessageList& msgs)
{
QSqlDatabase db = logDb();
if (!beginTransaction(db)) {
}
QList<int> senderIdList;
- QHash<QString, int> senderIds;
+ QHash<SenderData, qint64> senderIds;
QSqlQuery addSenderQuery;
- QSqlQuery selectSenderQuery;;
+ QSqlQuery selectSenderQuery;
+ ;
for (int i = 0; i < msgs.count(); i++) {
- const QString &sender = msgs.at(i).sender();
+ auto& msg = msgs.at(i);
+ SenderData sender = {msg.sender(), msg.realName(), msg.avatarUrl()};
if (senderIds.contains(sender)) {
senderIdList << senderIds[sender];
continue;
}
- selectSenderQuery = executePreparedQuery("select_senderid", sender, db);
+ QVariantList senderParams;
+ senderParams << sender.sender << sender.realname << sender.avatarurl;
+
+ selectSenderQuery = executePreparedQuery("select_senderid", senderParams, db);
if (selectSenderQuery.first()) {
- senderIdList << selectSenderQuery.value(0).toInt();
- senderIds[sender] = selectSenderQuery.value(0).toInt();
+ senderIdList << selectSenderQuery.value(0).toLongLong();
+ senderIds[sender] = selectSenderQuery.value(0).toLongLong();
}
else {
savePoint("sender_sp", db);
- addSenderQuery = executePreparedQuery("insert_sender", sender, db);
+ addSenderQuery = executePreparedQuery("insert_sender", senderParams, db);
if (addSenderQuery.lastError().isValid()) {
// seems it was inserted meanwhile... by a different thread
rollbackSavePoint("sender_sp", db);
- selectSenderQuery = executePreparedQuery("select_senderid", sender, db);
+ selectSenderQuery = executePreparedQuery("select_senderid", senderParams, db);
watchQuery(selectSenderQuery);
selectSenderQuery.first();
- senderIdList << selectSenderQuery.value(0).toInt();
- senderIds[sender] = selectSenderQuery.value(0).toInt();
+ senderIdList << selectSenderQuery.value(0).toLongLong();
+ senderIds[sender] = selectSenderQuery.value(0).toLongLong();
}
else {
releaseSavePoint("sender_sp", db);
addSenderQuery.first();
- senderIdList << addSenderQuery.value(0).toInt();
- senderIds[sender] = addSenderQuery.value(0).toInt();
+ senderIdList << addSenderQuery.value(0).toLongLong();
+ senderIds[sender] = addSenderQuery.value(0).toLongLong();
}
}
}
// yes we loop twice over the same list. This avoids alternating queries.
bool error = false;
for (int i = 0; i < msgs.count(); i++) {
- Message &msg = msgs[i];
+ Message& msg = msgs[i];
QVariantList params;
- params << msg.timestamp()
- << msg.bufferInfo().bufferId().toInt()
- << msg.type()
- << (int)msg.flags()
- << senderIdList.at(i)
- << msg.contents();
+ // PostgreSQL handles QDateTime()'s serialized format by default, and QDateTime() serializes
+ // to a 64-bit time compatible format by default.
+ params << msg.timestamp() << msg.bufferInfo().bufferId().toInt() << msg.type() << (int)msg.flags() << senderIdList.at(i)
+ << msg.senderPrefixes() << msg.contents();
QSqlQuery logMessageQuery = executePreparedQuery("insert_message", params, db);
if (!watchQuery(logMessageQuery)) {
db.rollback();
}
else {
logMessageQuery.first();
- msg.setMsgId(logMessageQuery.value(0).toInt());
+ msg.setMsgId(logMessageQuery.value(0).toLongLong());
}
}
return true;
}
-
QList<Message> PostgreSqlStorage::requestMsgs(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit)
{
QList<Message> messagelist;
QString queryName;
QVariantList params;
if (last == -1 && first == -1) {
- queryName = "select_messages";
+ queryName = "select_messagesNewestK";
}
else if (last == -1) {
queryName = "select_messagesNewerThan";
- params << first.toInt();
+ params << first.toQint64();
}
else {
queryName = "select_messagesRange";
- params << first.toInt();
- params << last.toInt();
+ params << first.toQint64();
+ params << last.toQint64();
}
params << bufferId.toInt();
if (limit != -1)
QDateTime timestamp;
while (query.next()) {
+ // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+ // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
timestamp = query.value(1).toDateTime();
timestamp.setTimeSpec(Qt::UTC);
Message msg(timestamp,
- bufferInfo,
- (Message::Type)query.value(2).toUInt(),
- query.value(5).toString(),
- query.value(4).toString(),
- (Message::Flags)query.value(3).toUInt());
- msg.setMsgId(query.value(0).toInt());
+ 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;
}
return messagelist;
}
+QList<Message> PostgreSqlStorage::requestMsgsFiltered(
+ UserId user, BufferId bufferId, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
+{
+ QList<Message> messagelist;
+
+ QSqlDatabase db = logDb();
+ if (!beginReadOnlyTransaction(db)) {
+ qWarning() << "PostgreSqlStorage::requestMsgs(): cannot start read only transaction!";
+ qWarning() << " -" << qPrintable(db.lastError().text());
+ return messagelist;
+ }
+
+ BufferInfo bufferInfo = getBufferInfo(user, bufferId);
+ if (!bufferInfo.isValid()) {
+ db.rollback();
+ return messagelist;
+ }
+
+ QSqlQuery query(db);
+ if (last == -1 && first == -1) {
+ query.prepare(queryString("select_messagesNewestK_filtered"));
+ }
+ else if (last == -1) {
+ query.prepare(queryString("select_messagesNewerThan_filtered"));
+ query.bindValue(":first", first.toQint64());
+ }
+ else {
+ query.prepare(queryString("select_messagesRange_filtered"));
+ query.bindValue(":last", last.toQint64());
+ query.bindValue(":first", first.toQint64());
+ }
+ query.bindValue(":buffer", bufferId.toInt());
+ query.bindValue(":limit", limit);
+ int typeRaw = type;
+ query.bindValue(":type", typeRaw);
+ int flagsRaw = flags;
+ query.bindValue(":flags", flagsRaw);
+
+ safeExec(query);
+ if (!watchQuery(query)) {
+ qDebug() << "select_messages failed";
+ db.rollback();
+ return messagelist;
+ }
+
+ QDateTime timestamp;
+ while (query.next()) {
+ // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+ // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
+ timestamp = query.value(1).toDateTime();
+ timestamp.setTimeSpec(Qt::UTC);
+ Message msg(timestamp,
+ 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;
+ }
+
+ db.commit();
+ return messagelist;
+}
QList<Message> PostgreSqlStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit)
{
// requestBuffers uses it's own transaction.
QHash<BufferId, BufferInfo> bufferInfoHash;
- foreach(BufferInfo bufferInfo, requestBuffers(user)) {
+ foreach (BufferInfo bufferInfo, requestBuffers(user)) {
bufferInfoHash[bufferInfo.bufferId()] = bufferInfo;
}
}
else {
query.prepare(queryString("select_messagesAll"));
- query.bindValue(":lastmsg", last.toInt());
+ query.bindValue(":lastmsg", last.toQint64());
}
query.bindValue(":userid", user.toInt());
- query.bindValue(":firstmsg", first.toInt());
+ query.bindValue(":firstmsg", first.toQint64());
safeExec(query);
if (!watchQuery(query)) {
db.rollback();
QDateTime timestamp;
for (int i = 0; i < limit && query.next(); i++) {
- timestamp = query.value(1).toDateTime();
+ // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+ // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
+ timestamp = query.value(2).toDateTime();
+ timestamp.setTimeSpec(Qt::UTC);
+ Message msg(timestamp,
+ 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;
+ }
+
+ db.commit();
+ return messagelist;
+}
+
+QList<Message> PostgreSqlStorage::requestAllMsgsFiltered(
+ UserId user, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
+{
+ QList<Message> messagelist;
+
+ // requestBuffers uses it's own transaction.
+ QHash<BufferId, BufferInfo> bufferInfoHash;
+ foreach (BufferInfo bufferInfo, requestBuffers(user)) {
+ bufferInfoHash[bufferInfo.bufferId()] = bufferInfo;
+ }
+
+ QSqlDatabase db = logDb();
+ if (!beginReadOnlyTransaction(db)) {
+ qWarning() << "PostgreSqlStorage::requestAllMsgs(): cannot start read only transaction!";
+ qWarning() << " -" << qPrintable(db.lastError().text());
+ return messagelist;
+ }
+
+ QSqlQuery query(db);
+ if (last == -1) {
+ query.prepare(queryString("select_messagesAllNew_filtered"));
+ }
+ else {
+ query.prepare(queryString("select_messagesAll_filtered"));
+ query.bindValue(":lastmsg", last.toQint64());
+ }
+ query.bindValue(":userid", user.toInt());
+ query.bindValue(":firstmsg", first.toQint64());
+
+ int typeRaw = type;
+ query.bindValue(":type", typeRaw);
+
+ int flagsRaw = flags;
+ query.bindValue(":flags", flagsRaw);
+
+ safeExec(query);
+ if (!watchQuery(query)) {
+ db.rollback();
+ return messagelist;
+ }
+
+ QDateTime timestamp;
+ for (int i = 0; i < limit && query.next(); i++) {
+ // PostgreSQL returns date/time in ISO 8601 format, no 64-bit handling needed
+ // See https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-DATETIME-OUTPUT
+ timestamp = query.value(2).toDateTime();
timestamp.setTimeSpec(Qt::UTC);
Message msg(timestamp,
- bufferInfoHash[query.value(1).toInt()],
- (Message::Type)query.value(3).toUInt(),
- query.value(6).toString(),
- query.value(5).toString(),
- (Message::Flags)query.value(4).toUInt());
- msg.setMsgId(query.value(0).toInt());
+ 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;
}
return messagelist;
}
+QMap<UserId, QString> PostgreSqlStorage::getAllAuthUserNames()
+{
+ QMap<UserId, QString> authusernames;
+ QSqlQuery query(logDb());
+ query.prepare(queryString("select_all_authusernames"));
+ safeExec(query);
+ watchQuery(query);
+
+ while (query.next()) {
+ authusernames[query.value(0).toInt()] = query.value(1).toString();
+ }
+ return authusernames;
+}
// void PostgreSqlStorage::safeExec(QSqlQuery &query) {
// qDebug() << "PostgreSqlStorage::safeExec";
// return;
// }
-
-bool PostgreSqlStorage::beginTransaction(QSqlDatabase &db)
+bool PostgreSqlStorage::beginTransaction(QSqlDatabase& db)
{
bool result = db.transaction();
if (!db.isOpen()) {
return result;
}
-bool PostgreSqlStorage::beginReadOnlyTransaction(QSqlDatabase &db)
+bool PostgreSqlStorage::beginReadOnlyTransaction(QSqlDatabase& db)
{
QSqlQuery query = db.exec("BEGIN TRANSACTION READ ONLY");
if (!db.isOpen()) {
return !query.lastError().isValid();
}
-
-QSqlQuery PostgreSqlStorage::prepareAndExecuteQuery(const QString &queryname, const QString ¶mstring, QSqlDatabase &db)
+QSqlQuery PostgreSqlStorage::prepareAndExecuteQuery(const QString& queryname, const QString& paramstring, QSqlDatabase& db)
{
// Query preparing is done lazily. That means that instead of always checking if the query is already prepared
// we just EXECUTE and catch the error
if (!db.isOpen()) {
db = logDb();
if (!beginTransaction(db)) {
- qWarning() << "PostgreSqlStorage::prepareAndExecuteQuery(): cannot start transaction while recovering from connection loss!";
+ qWarning()
+ << "PostgreSqlStorage::prepareAndExecuteQuery(): cannot start transaction while recovering from connection loss!";
qWarning() << " -" << qPrintable(db.lastError().text());
return query;
}
db.exec("SAVEPOINT quassel_prepare_query");
- } else {
+ }
+ else {
db.exec("ROLLBACK TO SAVEPOINT quassel_prepare_query");
}
// and once again: Qt leaves us without error codes so we either parse (language dependent(!)) strings
// or we just guess the error. As we're only interested in unprepared queries, this will be our guess. :)
- QSqlQuery checkQuery = db.exec(QString("SELECT count(name) FROM pg_prepared_statements WHERE name = 'quassel_%1' AND from_sql = TRUE").arg(queryname.toLower()));
+ QSqlQuery checkQuery = db.exec(
+ QString("SELECT count(name) FROM pg_prepared_statements WHERE name = 'quassel_%1' AND from_sql = TRUE").arg(queryname.toLower()));
checkQuery.first();
if (checkQuery.value(0).toInt() == 0) {
db.exec(QString("PREPARE quassel_%1 AS %2").arg(queryname).arg(queryString(queryname)));
return query;
}
-
-QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString &queryname, const QVariantList ¶ms, QSqlDatabase &db)
+QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString& queryname, const QVariantList& params, QSqlDatabase& db)
{
- QSqlDriver *driver = db.driver();
+ QSqlDriver* driver = db.driver();
QStringList paramStrings;
QSqlField field;
for (int i = 0; i < params.count(); i++) {
- const QVariant &value = params.at(i);
+ const QVariant& value = params.at(i);
field.setType(value.type());
if (value.isNull())
field.clear();
}
}
-
-QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString &queryname, const QVariant ¶m, QSqlDatabase &db)
+QSqlQuery PostgreSqlStorage::executePreparedQuery(const QString& queryname, const QVariant& param, QSqlDatabase& db)
{
QSqlField field;
field.setType(param.type());
return prepareAndExecuteQuery(queryname, paramString, db);
}
-
-void PostgreSqlStorage::deallocateQuery(const QString &queryname, const QSqlDatabase &db)
+void PostgreSqlStorage::deallocateQuery(const QString& queryname, const QSqlDatabase& db)
{
db.exec(QString("DEALLOCATE quassel_%1").arg(queryname));
}
-
-void PostgreSqlStorage::safeExec(QSqlQuery &query)
+void PostgreSqlStorage::safeExec(QSqlQuery& query)
{
// If the query fails due to the connection being gone, it seems to cause
// exec() to return false but no lastError to be set
- if(!query.exec() && !query.lastError().isValid())
- {
+ if (!query.exec() && !query.lastError().isValid()) {
QSqlDatabase db = logDb();
QSqlQuery retryQuery(db);
retryQuery.prepare(query.lastQuery());
QMapIterator<QString, QVariant> i(query.boundValues());
- while (i.hasNext())
- {
+ while (i.hasNext()) {
i.next();
- retryQuery.bindValue(i.key(),i.value());
+ retryQuery.bindValue(i.key(), i.value());
}
query = retryQuery;
query.exec();
// ========================================
PostgreSqlMigrationWriter::PostgreSqlMigrationWriter()
: PostgreSqlStorage()
-{
-}
-
+{}
bool PostgreSqlMigrationWriter::prepareQuery(MigrationObject mo)
{
case UserSetting:
query = queryString("migrate_write_usersetting");
break;
+ case CoreState:
+ query = queryString("migrate_write_corestate");
+ break;
}
newQuery(query, logDb());
return true;
}
-
-//bool PostgreSqlMigrationWriter::writeUser(const QuasselUserMO &user) {
-bool PostgreSqlMigrationWriter::writeMo(const QuasselUserMO &user)
+// bool PostgreSqlMigrationWriter::writeUser(const QuasselUserMO &user) {
+bool PostgreSqlMigrationWriter::writeMo(const QuasselUserMO& user)
{
bindValue(0, user.id.toInt());
bindValue(1, user.username);
bindValue(2, user.password);
+ bindValue(3, user.hashversion);
+ bindValue(4, user.authenticator);
return exec();
}
-
-//bool PostgreSqlMigrationWriter::writeSender(const SenderMO &sender) {
-bool PostgreSqlMigrationWriter::writeMo(const SenderMO &sender)
+// bool PostgreSqlMigrationWriter::writeSender(const SenderMO &sender) {
+bool PostgreSqlMigrationWriter::writeMo(const SenderMO& sender)
{
bindValue(0, sender.senderId);
bindValue(1, sender.sender);
+ bindValue(2, sender.realname);
+ bindValue(3, sender.avatarurl);
return exec();
}
-
-//bool PostgreSqlMigrationWriter::writeIdentity(const IdentityMO &identity) {
-bool PostgreSqlMigrationWriter::writeMo(const IdentityMO &identity)
+// bool PostgreSqlMigrationWriter::writeIdentity(const IdentityMO &identity) {
+bool PostgreSqlMigrationWriter::writeMo(const IdentityMO& identity)
{
_validIdentities << identity.id.toInt();
bindValue(0, identity.id.toInt());
bindValue(11, identity.autoAwayReasonEnabled);
bindValue(12, identity.detachAwayEnabled);
bindValue(13, identity.detachAwayReason);
- bindValue(14, identity.detchAwayReasonEnabled);
+ bindValue(14, identity.detachAwayReasonEnabled);
bindValue(15, identity.ident);
bindValue(16, identity.kickReason);
bindValue(17, identity.partReason);
return exec();
}
-
-//bool PostgreSqlMigrationWriter::writeIdentityNick(const IdentityNickMO &identityNick) {
-bool PostgreSqlMigrationWriter::writeMo(const IdentityNickMO &identityNick)
+// bool PostgreSqlMigrationWriter::writeIdentityNick(const IdentityNickMO &identityNick) {
+bool PostgreSqlMigrationWriter::writeMo(const IdentityNickMO& identityNick)
{
bindValue(0, identityNick.nickid);
bindValue(1, identityNick.identityId.toInt());
return exec();
}
-
-//bool PostgreSqlMigrationWriter::writeNetwork(const NetworkMO &network) {
-bool PostgreSqlMigrationWriter::writeMo(const NetworkMO &network)
+// bool PostgreSqlMigrationWriter::writeNetwork(const NetworkMO &network) {
+bool PostgreSqlMigrationWriter::writeMo(const NetworkMO& network)
{
bindValue(0, network.networkid.toInt());
bindValue(1, network.userid.toInt());
bindValue(22, network.usesasl);
bindValue(23, network.saslaccount);
bindValue(24, network.saslpassword);
+ // Custom rate limiting
+ bindValue(25, network.usecustommessagerate);
+ bindValue(26, network.messagerateburstsize);
+ bindValue(27, network.messageratedelay);
+ bindValue(28, network.unlimitedmessagerate);
return exec();
}
-
-//bool PostgreSqlMigrationWriter::writeBuffer(const BufferMO &buffer) {
-bool PostgreSqlMigrationWriter::writeMo(const BufferMO &buffer)
+// bool PostgreSqlMigrationWriter::writeBuffer(const BufferMO &buffer) {
+bool PostgreSqlMigrationWriter::writeMo(const BufferMO& buffer)
{
bindValue(0, buffer.bufferid.toInt());
bindValue(1, buffer.userid.toInt());
bindValue(4, buffer.buffername);
bindValue(5, buffer.buffercname);
bindValue(6, (int)buffer.buffertype);
- bindValue(7, buffer.lastseenmsgid);
- bindValue(8, buffer.markerlinemsgid);
- bindValue(9, buffer.key);
- bindValue(10, buffer.joined);
+ bindValue(7, buffer.lastmsgid);
+ bindValue(8, buffer.lastseenmsgid);
+ bindValue(9, buffer.markerlinemsgid);
+ bindValue(10, buffer.bufferactivity);
+ bindValue(11, buffer.highlightcount);
+ bindValue(12, buffer.key);
+ bindValue(13, buffer.joined);
+ bindValue(14, buffer.cipher);
return exec();
}
-
-//bool PostgreSqlMigrationWriter::writeBacklog(const BacklogMO &backlog) {
-bool PostgreSqlMigrationWriter::writeMo(const BacklogMO &backlog)
+// bool PostgreSqlMigrationWriter::writeBacklog(const BacklogMO &backlog) {
+bool PostgreSqlMigrationWriter::writeMo(const BacklogMO& backlog)
{
- bindValue(0, backlog.messageid.toInt());
+ bindValue(0, backlog.messageid.toQint64());
bindValue(1, backlog.time);
bindValue(2, backlog.bufferid.toInt());
bindValue(3, backlog.type);
bindValue(4, (int)backlog.flags);
bindValue(5, backlog.senderid);
- bindValue(6, backlog.message);
+ bindValue(6, backlog.senderprefixes);
+ bindValue(7, backlog.message);
return exec();
}
-
-//bool PostgreSqlMigrationWriter::writeIrcServer(const IrcServerMO &ircserver) {
-bool PostgreSqlMigrationWriter::writeMo(const IrcServerMO &ircserver)
+// bool PostgreSqlMigrationWriter::writeIrcServer(const IrcServerMO &ircserver) {
+bool PostgreSqlMigrationWriter::writeMo(const IrcServerMO& ircserver)
{
bindValue(0, ircserver.serverid);
bindValue(1, ircserver.userid.toInt());
bindValue(11, ircserver.proxyport);
bindValue(12, ircserver.proxyuser);
bindValue(13, ircserver.proxypass);
+ bindValue(14, ircserver.sslverify);
return exec();
}
-
-//bool PostgreSqlMigrationWriter::writeUserSetting(const UserSettingMO &userSetting) {
-bool PostgreSqlMigrationWriter::writeMo(const UserSettingMO &userSetting)
+// bool PostgreSqlMigrationWriter::writeUserSetting(const UserSettingMO &userSetting) {
+bool PostgreSqlMigrationWriter::writeMo(const UserSettingMO& userSetting)
{
bindValue(0, userSetting.userid.toInt());
bindValue(1, userSetting.settingname);
return exec();
}
+bool PostgreSqlMigrationWriter::writeMo(const CoreStateMO& coreState)
+{
+ bindValue(0, coreState.key);
+ bindValue(1, coreState.value);
+ return exec();
+}
bool PostgreSqlMigrationWriter::postProcess()
{
QSqlDatabase db = logDb();
QList<Sequence> sequences;
- sequences << Sequence("backlog", "messageid")
- << Sequence("buffer", "bufferid")
- << Sequence("identity", "identityid")
- << Sequence("identity_nick", "nickid")
- << Sequence("ircserver", "serverid")
- << Sequence("network", "networkid")
- << Sequence("quasseluser", "userid")
- << Sequence("sender", "senderid");
+ sequences << Sequence("backlog", "messageid") << Sequence("buffer", "bufferid") << Sequence("identity", "identityid")
+ << Sequence("identity_nick", "nickid") << Sequence("ircserver", "serverid") << Sequence("network", "networkid")
+ << Sequence("quasseluser", "userid") << Sequence("sender", "senderid");
QList<Sequence>::const_iterator iter;
for (iter = sequences.constBegin(); iter != sequences.constEnd(); ++iter) {
resetQuery();
if (!exec())
return false;
}
+
+ // Update the lastmsgid for all existing buffers.
+ resetQuery();
+ newQuery(QString("SELECT populate_lastmsgid()"), db);
+ if (!exec())
+ return false;
return true;
}