/***************************************************************************
- * 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 "logmessage.h"
#include "network.h"
#include "quassel.h"
}
-AbstractSqlMigrationWriter *PostgreSqlStorage::createMigrationWriter()
+std::unique_ptr<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")) {
+ quWarning() << 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::description() const
+QString PostgreSqlStorage::displayName() const
{
- // FIXME: proper description
- return tr("PostgreSQL Turbo Bomber HD!");
+ return backendId(); // Note: Pre-0.13 clients use the displayName property for backend idenfication
}
-QStringList PostgreSqlStorage::setupKeys() const
+QString PostgreSqlStorage::description() const
{
- QStringList keys;
- keys << "Username"
- << "Password"
- << "Hostname"
- << "Port"
- << "Database";
- return keys;
+ // FIXME: proper description
+ return tr("PostgreSQL Turbo Bomber HD!");
}
-QVariantMap PostgreSqlStorage::setupDefaults() const
+QVariantList PostgreSqlStorage::setupData() const
{
- QVariantMap map;
- map["Username"] = QVariant(QString("quassel"));
- map["Hostname"] = QVariant(QString("localhost"));
- map["Port"] = QVariant(5432);
- map["Database"] = QVariant(QString("quassel"));
- return map;
+ 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;
}
}
-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();
+ }
}
}
-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;
}
}
+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::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");
+ }
+
+ 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;
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());
}
query.bindValue(":proxyport", server.proxyPort);
query.bindValue(":proxyuser", server.proxyUser);
query.bindValue(":proxypass", server.proxyPass);
+ query.bindValue(":sslverify", server.sslVerify);
}
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;
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);
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);
query.bindValue(":userid", user.toInt());
query.bindValue(":bufferid", bufferId.toInt());
- query.bindValue(":lastseenmsgid", msgId.toInt());
+ query.bindValue(":lastseenmsgid", msgId.toQint64());
safeExec(query);
watchQuery(query);
}
}
while (query.next()) {
- lastSeenHash[query.value(0).toInt()] = query.value(1).toInt();
+ lastSeenHash[query.value(0).toInt()] = query.value(1).toLongLong();
}
db.commit();
query.bindValue(":userid", user.toInt());
query.bindValue(":bufferid", bufferId.toInt());
- query.bindValue(":markerlinemsgid", msgId.toInt());
+ query.bindValue(":markerlinemsgid", msgId.toQint64());
safeExec(query);
watchQuery(query);
}
}
while (query.next()) {
- markerLineHash[query.value(0).toInt()] = query.value(1).toInt();
+ markerLineHash[query.value(0).toInt()] = query.value(1).toLongLong();
}
db.commit();
}
+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(0);
+ if (query.first())
+ result = Message::Types(query.value(0).toInt());
+ return result;
+}
+
+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);
+ int result = int(0);
+ if (query.first())
+ result = query.value(0).toInt();
+ return result;
+}
+
bool PostgreSqlStorage::logMessage(Message &msg)
{
QSqlDatabase db = logDb();
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;
+ // 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);
}
QList<int> senderIdList;
- QHash<QString, int> senderIds;
+ QHash<SenderData, qint64> senderIds;
QSqlQuery addSenderQuery;
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();
}
}
}
for (int i = 0; i < msgs.count(); i++) {
Message &msg = msgs[i];
QVariantList params;
+ // 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)) {
}
else {
logMessageQuery.first();
- msg.setMsgId(logMessageQuery.value(0).toInt());
+ msg.setMsgId(logMessageQuery.value(0).toLongLong());
}
}
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(),
+ (Message::Type)query.value(2).toInt(),
+ query.value(8).toString(),
query.value(4).toString(),
- (Message::Flags)query.value(3).toUInt());
- msg.setMsgId(query.value(0).toInt());
+ 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::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;
}
}
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).toUInt(),
- query.value(6).toString(),
+ (Message::Type)query.value(3).toInt(),
+ query.value(9).toString(),
query.value(5).toString(),
- (Message::Flags)query.value(4).toUInt());
- msg.setMsgId(query.value(0).toInt());
+ 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;
}
}
+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).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;
+}
+
+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";
// qDebug() << " executing:\n" << query.executedQuery();
case UserSetting:
query = queryString("migrate_write_usersetting");
break;
+ case CoreState:
+ query = queryString("migrate_write_corestate");
+ break;
}
newQuery(query, logDb());
return true;
bindValue(0, user.id.toInt());
bindValue(1, user.username);
bindValue(2, user.password);
+ bindValue(3, user.hashversion);
+ bindValue(4, user.authenticator);
return exec();
}
{
bindValue(0, sender.senderId);
bindValue(1, sender.sender);
+ bindValue(2, sender.realname);
+ bindValue(3, sender.avatarurl);
return exec();
}
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);
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();
}
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)
{
- 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();
}
bindValue(11, ircserver.proxyport);
bindValue(12, ircserver.proxyuser);
bindValue(13, ircserver.proxypass);
+ bindValue(14, ircserver.sslverify);
return exec();
}
return exec();
}
+bool PostgreSqlMigrationWriter::writeMo(const CoreStateMO &coreState)
+{
+ bindValue(0, coreState.key);
+ bindValue(1, coreState.value);
+ return exec();
+}
+
bool PostgreSqlMigrationWriter::postProcess()
{
if (!exec())
return false;
}
+
+ // Update the lastmsgid for all existing buffers.
+ resetQuery();
+ newQuery(QString("SELECT populate_lastmsgid()"), db);
+ if (!exec())
+ return false;
return true;
}