Implement type-filtered backlog fetching
authorJanne Koschinski <janne@kuschku.de>
Tue, 8 May 2018 20:50:41 +0000 (15:50 -0500)
committerManuel Nickschas <sputnick@quassel-irc.org>
Wed, 23 May 2018 22:33:28 +0000 (00:33 +0200)
Add new backlog fetching methods that only return messages of the
specified types.  This allows clients to only fetch the types of
messages that they need, e.g. if join/part/quit is hidden.

This is not yet used in Quassel itself, but third-party clients
including QuasselDroid use this for better performance on limited
bandwidth networks.

Signed-off-by: Janne Koschinski <janne@kuschku.de>
Closes GH-339.

22 files changed:
src/common/backlogmanager.cpp
src/common/backlogmanager.h
src/common/quassel.h
src/core/SQL/PostgreSQL/select_messagesAllNew_filtered.sql [new file with mode: 0644]
src/core/SQL/PostgreSQL/select_messagesAll_filtered.sql [new file with mode: 0644]
src/core/SQL/PostgreSQL/select_messagesNewerThan_filtered.sql [new file with mode: 0644]
src/core/SQL/PostgreSQL/select_messagesNewestK_filtered.sql [new file with mode: 0644]
src/core/SQL/PostgreSQL/select_messagesRange_filtered.sql [new file with mode: 0644]
src/core/SQL/SQLite/select_messagesAllNew_filtered.sql [new file with mode: 0644]
src/core/SQL/SQLite/select_messagesAll_filtered.sql [new file with mode: 0644]
src/core/SQL/SQLite/select_messagesNewerThan_filtered.sql [new file with mode: 0644]
src/core/SQL/SQLite/select_messagesNewestK_filtered.sql [new file with mode: 0644]
src/core/SQL/SQLite/select_messagesRange_filtered.sql [new file with mode: 0644]
src/core/core.h
src/core/corebacklogmanager.cpp
src/core/corebacklogmanager.h
src/core/postgresqlstorage.cpp
src/core/postgresqlstorage.h
src/core/sql.qrc
src/core/sqlitestorage.cpp
src/core/sqlitestorage.h
src/core/storage.h

index 10717cf..2ea49d5 100644 (file)
@@ -27,9 +27,20 @@ QVariantList BacklogManager::requestBacklog(BufferId bufferId, MsgId first, MsgI
     return QVariantList();
 }
 
     return QVariantList();
 }
 
+QVariantList BacklogManager::requestBacklogFiltered(BufferId bufferId, MsgId first, MsgId last, int limit, int additional, int type, int flags)
+{
+    REQUEST(ARG(bufferId), ARG(first), ARG(last), ARG(limit), ARG(additional), ARG(type), ARG(flags))
+    return QVariantList();
+}
 
 QVariantList BacklogManager::requestBacklogAll(MsgId first, MsgId last, int limit, int additional)
 {
     REQUEST(ARG(first), ARG(last), ARG(limit), ARG(additional))
     return QVariantList();
 }
 
 QVariantList BacklogManager::requestBacklogAll(MsgId first, MsgId last, int limit, int additional)
 {
     REQUEST(ARG(first), ARG(last), ARG(limit), ARG(additional))
     return QVariantList();
 }
+
+QVariantList BacklogManager::requestBacklogAllFiltered(MsgId first, MsgId last, int limit, int additional, int type, int flags)
+{
+    REQUEST(ARG(first), ARG(last), ARG(limit), ARG(additional), ARG(type), ARG(flags))
+    return QVariantList();
+}
index d92180d..1aa5d43 100644 (file)
@@ -35,10 +35,14 @@ public:
 
 public slots:
     virtual QVariantList requestBacklog(BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1, int additional = 0);
 
 public slots:
     virtual QVariantList requestBacklog(BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1, int additional = 0);
+    virtual QVariantList requestBacklogFiltered(BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1, int additional = 0, int type = -1, int flags = -1);
     inline virtual void receiveBacklog(BufferId, MsgId, MsgId, int, int, QVariantList) {};
     inline virtual void receiveBacklog(BufferId, MsgId, MsgId, int, int, QVariantList) {};
+    inline virtual void receiveBacklogFiltered(BufferId, MsgId, MsgId, int, int, int, int, QVariantList) {};
 
     virtual QVariantList requestBacklogAll(MsgId first = -1, MsgId last = -1, int limit = -1, int additional = 0);
 
     virtual QVariantList requestBacklogAll(MsgId first = -1, MsgId last = -1, int limit = -1, int additional = 0);
+    virtual QVariantList requestBacklogAllFiltered(MsgId first = -1, MsgId last = -1, int limit = -1, int additional = 0, int type = -1, int flags = -1);
     inline virtual void receiveBacklogAll(MsgId, MsgId, int, int, QVariantList) {};
     inline virtual void receiveBacklogAll(MsgId, MsgId, int, int, QVariantList) {};
+    inline virtual void receiveBacklogAllFiltered(MsgId, MsgId, int, int, int, int, QVariantList) {};
 
 signals:
     void backlogRequested(BufferId, MsgId, MsgId, int, int);
 
 signals:
     void backlogRequested(BufferId, MsgId, MsgId, int, int);
index fd91f9a..dc697fc 100644 (file)
@@ -133,6 +133,7 @@ public:
         ExtendedFeatures,         ///< Extended features
         LongMessageTime,          ///< Serialize message time as 64-bit
         RichMessages,             ///< Real Name and Avatar URL in backlog
         ExtendedFeatures,         ///< Extended features
         LongMessageTime,          ///< Serialize message time as 64-bit
         RichMessages,             ///< Real Name and Avatar URL in backlog
+        BacklogFilterType,        ///< BacklogManager supports filtering backlog by MessageType
 #if QT_VERSION >= 0x050500
         EcdsaCertfpKeys,          ///< ECDSA keys for CertFP in identities
 #endif
 #if QT_VERSION >= 0x050500
         EcdsaCertfpKeys,          ///< ECDSA keys for CertFP in identities
 #endif
diff --git a/src/core/SQL/PostgreSQL/select_messagesAllNew_filtered.sql b/src/core/SQL/PostgreSQL/select_messagesAllNew_filtered.sql
new file mode 100644 (file)
index 0000000..780263f
--- /dev/null
@@ -0,0 +1,9 @@
+SELECT messageid, bufferid, time,  type, flags, sender, senderprefixes, realname, avatarurl, message
+FROM backlog
+JOIN sender ON backlog.senderid = sender.senderid
+WHERE backlog.bufferid IN (SELECT bufferid FROM buffer WHERE userid = :userid)
+    AND backlog.messageid >= :firstmsg
+    AND backlog.type & :type != 0
+    AND (:flags = 0 OR backlog.flags & :flags != 0)
+ORDER BY messageid DESC
+-- Unlike SQLite, no LIMIT clause, mimicking the unfiltered version - investigate later..?
diff --git a/src/core/SQL/PostgreSQL/select_messagesAll_filtered.sql b/src/core/SQL/PostgreSQL/select_messagesAll_filtered.sql
new file mode 100644 (file)
index 0000000..3e1ce65
--- /dev/null
@@ -0,0 +1,10 @@
+SELECT messageid, bufferid, time,  type, flags, sender, senderprefixes, realname, avatarurl, message
+FROM backlog
+JOIN sender ON backlog.senderid = sender.senderid
+WHERE backlog.bufferid IN (SELECT bufferid FROM buffer WHERE userid = :userid)
+    AND backlog.messageid >= :firstmsg
+    AND backlog.messageid < :lastmsg
+    AND backlog.type & :type != 0
+    AND (:flags = 0 OR backlog.flags & :flags != 0)
+ORDER BY messageid DESC
+-- Unlike SQLite, no LIMIT clause, mimicking the unfiltered version - investigate later..?
diff --git a/src/core/SQL/PostgreSQL/select_messagesNewerThan_filtered.sql b/src/core/SQL/PostgreSQL/select_messagesNewerThan_filtered.sql
new file mode 100644 (file)
index 0000000..46b4d47
--- /dev/null
@@ -0,0 +1,10 @@
+SELECT messageid, time,  type, flags, sender, senderprefixes, realname, avatarurl, message
+FROM backlog
+JOIN sender ON backlog.senderid = sender.senderid
+WHERE backlog.messageid >= :first
+    AND backlog.messageid <= (SELECT buffer.lastmsgid FROM buffer WHERE buffer.bufferid = :buffer)
+    AND bufferid = :buffer
+    AND backlog.type & :type != 0
+    AND (:flags = 0 OR backlog.flags & :flags != 0)
+ORDER BY messageid DESC
+LIMIT :limit
diff --git a/src/core/SQL/PostgreSQL/select_messagesNewestK_filtered.sql b/src/core/SQL/PostgreSQL/select_messagesNewestK_filtered.sql
new file mode 100644 (file)
index 0000000..cdb960c
--- /dev/null
@@ -0,0 +1,9 @@
+SELECT messageid, time,  type, flags, sender, senderprefixes, realname, avatarurl, message
+FROM backlog
+JOIN sender ON backlog.senderid = sender.senderid
+WHERE bufferid = :buffer
+    AND backlog.messageid <= (SELECT buffer.lastmsgid FROM buffer WHERE buffer.bufferid = :buffer)
+    AND backlog.type & :type != 0
+    AND (:flags = 0 OR backlog.flags & :flags != 0)
+ORDER BY messageid DESC
+LIMIT :limit
diff --git a/src/core/SQL/PostgreSQL/select_messagesRange_filtered.sql b/src/core/SQL/PostgreSQL/select_messagesRange_filtered.sql
new file mode 100644 (file)
index 0000000..6030e53
--- /dev/null
@@ -0,0 +1,10 @@
+SELECT messageid, time,  type, flags, sender, senderprefixes, realname, avatarurl, message
+FROM backlog
+JOIN sender ON backlog.senderid = sender.senderid
+WHERE backlog.messageid >= :first
+    AND backlog.messageid < :last
+    AND bufferid = :buffer
+    AND backlog.type & :type != 0
+    AND (:flags = 0 OR backlog.flags & :flags != 0)
+ORDER BY messageid DESC
+LIMIT :limit
diff --git a/src/core/SQL/SQLite/select_messagesAllNew_filtered.sql b/src/core/SQL/SQLite/select_messagesAllNew_filtered.sql
new file mode 100644 (file)
index 0000000..1a742b8
--- /dev/null
@@ -0,0 +1,9 @@
+SELECT messageid, bufferid, time,  type, flags, sender, senderprefixes, realname, avatarurl, message
+FROM backlog
+JOIN sender ON backlog.senderid = sender.senderid
+WHERE backlog.bufferid IN (SELECT bufferid FROM buffer WHERE userid = :userid)
+    AND backlog.messageid >= :firstmsg
+    AND backlog.type & :type != 0
+    AND (:flags = 0 OR backlog.flags & :flags != 0)
+ORDER BY messageid DESC
+LIMIT :limit
diff --git a/src/core/SQL/SQLite/select_messagesAll_filtered.sql b/src/core/SQL/SQLite/select_messagesAll_filtered.sql
new file mode 100644 (file)
index 0000000..c09be6b
--- /dev/null
@@ -0,0 +1,10 @@
+SELECT messageid, bufferid, time,  type, flags, sender, senderprefixes, realname, avatarurl, message
+FROM backlog
+JOIN sender ON backlog.senderid = sender.senderid
+WHERE backlog.bufferid IN (SELECT bufferid FROM buffer WHERE userid = :userid)
+    AND backlog.messageid >= :firstmsg
+    AND backlog.messageid < :lastmsg
+    AND backlog.type & :type != 0
+    AND (:flags = 0 OR backlog.flags & :flags != 0)
+ORDER BY messageid DESC
+LIMIT :limit
diff --git a/src/core/SQL/SQLite/select_messagesNewerThan_filtered.sql b/src/core/SQL/SQLite/select_messagesNewerThan_filtered.sql
new file mode 100644 (file)
index 0000000..198df7c
--- /dev/null
@@ -0,0 +1,10 @@
+SELECT messageid, time,  type, flags, sender, senderprefixes, realname, avatarurl, message
+FROM backlog
+JOIN sender ON backlog.senderid = sender.senderid
+WHERE backlog.messageid >= :firstmsg
+    AND backlog.messageid <= (SELECT buffer.lastmsgid FROM buffer WHERE buffer.bufferid = :bufferid)
+    AND bufferid = :bufferid
+    AND backlog.type & :type != 0
+    AND (:flags = 0 OR backlog.flags & :flags != 0)
+ORDER BY messageid DESC
+LIMIT :limit
diff --git a/src/core/SQL/SQLite/select_messagesNewestK_filtered.sql b/src/core/SQL/SQLite/select_messagesNewestK_filtered.sql
new file mode 100644 (file)
index 0000000..b4411af
--- /dev/null
@@ -0,0 +1,9 @@
+SELECT messageid, time,  type, flags, sender, senderprefixes, realname, avatarurl, message
+FROM backlog
+JOIN sender ON backlog.senderid = sender.senderid
+WHERE bufferid = :bufferid
+AND backlog.messageid <= (SELECT buffer.lastmsgid FROM buffer WHERE buffer.bufferid = :bufferid)
+AND backlog.type & :type != 0
+AND (:flags = 0 OR backlog.flags & :flags != 0)
+ORDER BY messageid DESC
+LIMIT :limit
diff --git a/src/core/SQL/SQLite/select_messagesRange_filtered.sql b/src/core/SQL/SQLite/select_messagesRange_filtered.sql
new file mode 100644 (file)
index 0000000..d1e4c0f
--- /dev/null
@@ -0,0 +1,10 @@
+SELECT messageid, time,  type, flags, sender, senderprefixes, realname, avatarurl, message
+FROM backlog
+JOIN sender ON backlog.senderid = sender.senderid
+WHERE bufferid = :bufferid
+    AND backlog.messageid >= :firstmsg
+    AND backlog.messageid < :lastmsg
+    AND backlog.type & :type != 0
+    AND (:flags = 0 OR backlog.flags & :flags != 0)
+ORDER BY messageid DESC
+LIMIT :limit
index 640ba18..0814e7c 100644 (file)
@@ -429,6 +429,22 @@ public:
     }
 
 
     }
 
 
+    //! Request a certain number messages stored in a given buffer, matching certain filters
+    /** \param buffer   The buffer we request messages from
+     *  \param first    if != -1 return only messages with a MsgId >= first
+     *  \param last     if != -1 return only messages with a MsgId < last
+     *  \param limit    if != -1 limit the returned list to a max of \limit entries
+     *  \param type     The Message::Types that should be returned
+     *  \return The requested list of messages
+     */
+    static inline QList<Message> requestMsgsFiltered(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1,
+                                                     int limit = -1, Message::Types type = Message::Types{-1},
+                                                     Message::Flags flags = Message::Flags{-1})
+    {
+        return instance()->_storage->requestMsgsFiltered(user, bufferId, first, last, limit, type, flags);
+    }
+
+
     //! Request a certain number of messages across all buffers
     /** \param first    if != -1 return only messages with a MsgId >= first
      *  \param last     if != -1 return only messages with a MsgId < last
     //! Request a certain number of messages across all buffers
     /** \param first    if != -1 return only messages with a MsgId >= first
      *  \param last     if != -1 return only messages with a MsgId < last
@@ -441,6 +457,21 @@ public:
     }
 
 
     }
 
 
+    //! Request a certain number of messages across all buffers, matching certain filters
+    /** \param first    if != -1 return only messages with a MsgId >= first
+     *  \param last     if != -1 return only messages with a MsgId < last
+     *  \param limit    Max amount of messages
+     *  \param type     The Message::Types that should be returned
+     *  \return The requested list of messages
+     */
+    static inline QList<Message> requestAllMsgsFiltered(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1,
+                                                        Message::Types type = Message::Types{-1},
+                                                        Message::Flags flags = Message::Flags{-1})
+    {
+        return instance()->_storage->requestAllMsgsFiltered(user, first, last, limit, type, flags);
+    }
+
+
     //! Request a list of all buffers known to a user.
     /** This method is used to get a list of all buffers we have stored a backlog from.
      *  \note This method is threadsafe.
     //! Request a list of all buffers known to a user.
     /** This method is used to get a list of all buffers we have stored a backlog from.
      *  \note This method is threadsafe.
index d0fa48d..73e1805 100644 (file)
@@ -78,6 +78,52 @@ QVariantList CoreBacklogManager::requestBacklog(BufferId bufferId, MsgId first,
 }
 
 
 }
 
 
+QVariantList CoreBacklogManager::requestBacklogFiltered(BufferId bufferId, MsgId first, MsgId last, int limit, int additional, int type, int flags)
+{
+    QVariantList backlog;
+    QList<Message> msgList;
+    msgList = Core::requestMsgsFiltered(coreSession()->user(), bufferId, first, last, limit, Message::Types{type}, Message::Flags{flags});
+
+    QList<Message>::const_iterator msgIter = msgList.constBegin();
+    QList<Message>::const_iterator msgListEnd = msgList.constEnd();
+    while (msgIter != msgListEnd) {
+        backlog << qVariantFromValue(*msgIter);
+        ++msgIter;
+    }
+
+    if (additional && limit != 0) {
+        MsgId oldestMessage = first;
+        if (!msgList.isEmpty()) {
+            if (msgList.first().msgId() < msgList.last().msgId())
+                oldestMessage = msgList.first().msgId();
+            else
+                oldestMessage = msgList.last().msgId();
+        }
+
+        if (first != -1) {
+            last = first;
+        }
+        else {
+            last = oldestMessage;
+        }
+
+        // only fetch additional messages if they continue seemlessly
+        // that is, if the list of messages is not truncated by the limit
+        if (last == oldestMessage) {
+            msgList = Core::requestMsgsFiltered(coreSession()->user(), bufferId, -1, last, additional, Message::Types{type}, Message::Flags{flags});
+            msgIter = msgList.constBegin();
+            msgListEnd = msgList.constEnd();
+            while (msgIter != msgListEnd) {
+                backlog << qVariantFromValue(*msgIter);
+                ++msgIter;
+            }
+        }
+    }
+
+    return backlog;
+}
+
+
 QVariantList CoreBacklogManager::requestBacklogAll(MsgId first, MsgId last, int limit, int additional)
 {
     QVariantList backlog;
 QVariantList CoreBacklogManager::requestBacklogAll(MsgId first, MsgId last, int limit, int additional)
 {
     QVariantList backlog;
@@ -115,3 +161,43 @@ QVariantList CoreBacklogManager::requestBacklogAll(MsgId first, MsgId last, int
 
     return backlog;
 }
 
     return backlog;
 }
+
+
+QVariantList CoreBacklogManager::requestBacklogAllFiltered(MsgId first, MsgId last, int limit, int additional, int type,
+                                                           int flags)
+{
+    QVariantList backlog;
+    QList<Message> msgList;
+    msgList = Core::requestAllMsgsFiltered(coreSession()->user(), first, last, limit, Message::Types{type}, Message::Flags{flags});
+
+    QList<Message>::const_iterator msgIter = msgList.constBegin();
+    QList<Message>::const_iterator msgListEnd = msgList.constEnd();
+    while (msgIter != msgListEnd) {
+        backlog << qVariantFromValue(*msgIter);
+        ++msgIter;
+    }
+
+    if (additional) {
+        if (first != -1) {
+            last = first;
+        }
+        else {
+            last = -1;
+            if (!msgList.isEmpty()) {
+                if (msgList.first().msgId() < msgList.last().msgId())
+                    last = msgList.first().msgId();
+                else
+                    last = msgList.last().msgId();
+            }
+        }
+        msgList = Core::requestAllMsgsFiltered(coreSession()->user(), -1, last, additional, Message::Types{type}, Message::Flags{flags});
+        msgIter = msgList.constBegin();
+        msgListEnd = msgList.constEnd();
+        while (msgIter != msgListEnd) {
+            backlog << qVariantFromValue(*msgIter);
+            ++msgIter;
+        }
+    }
+
+    return backlog;
+}
index a124016..f314868 100644 (file)
@@ -37,7 +37,11 @@ public:
 
 public slots:
     virtual QVariantList requestBacklog(BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1, int additional = 0);
 
 public slots:
     virtual QVariantList requestBacklog(BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1, int additional = 0);
+    QVariantList requestBacklogFiltered(BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1,
+                                        int additional = 0, int type = -1, int flags = -1) override;
     virtual QVariantList requestBacklogAll(MsgId first = -1, MsgId last = -1, int limit = -1, int additional = 0);
     virtual QVariantList requestBacklogAll(MsgId first = -1, MsgId last = -1, int limit = -1, int additional = 0);
+    QVariantList requestBacklogAllFiltered(MsgId first = -1, MsgId last = -1, int limit = -1, int additional = 0,
+                                           int type = -1, int flags = -1) override;
 
 private:
     CoreSession *_coreSession;
 
 private:
     CoreSession *_coreSession;
index 3c15b2c..5b52afd 100644 (file)
@@ -1755,6 +1755,70 @@ QList<Message> PostgreSqlStorage::requestMsgs(UserId user, BufferId bufferId, Ms
 }
 
 
 }
 
 
+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.toInt());
+    } else {
+        query.prepare(queryString("select_messagesRange_filtered"));
+        query.bindValue(":last", last.toInt());
+        query.bindValue(":first", first.toInt());
+    }
+    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()) {
+        timestamp = query.value(1).toDateTime();
+        timestamp.setTimeSpec(Qt::UTC);
+        Message msg(timestamp,
+                    bufferInfo,
+                    (Message::Type)query.value(2).toUInt(),
+                    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).toInt());
+        messagelist << msg;
+    }
+
+    db.commit();
+    return messagelist;
+}
+
+
 QList<Message> PostgreSqlStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit)
 {
     QList<Message> messagelist;
 QList<Message> PostgreSqlStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit)
 {
     QList<Message> messagelist;
@@ -1810,6 +1874,67 @@ QList<Message> PostgreSqlStorage::requestAllMsgs(UserId user, MsgId first, MsgId
 }
 
 
 }
 
 
+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.toInt());
+    }
+    query.bindValue(":userid", user.toInt());
+    query.bindValue(":firstmsg", first.toInt());
+
+    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++) {
+        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(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).toInt());
+        messagelist << msg;
+    }
+
+    db.commit();
+    return messagelist;
+}
+
 QMap<UserId, QString> PostgreSqlStorage::getAllAuthUserNames()
 {
     QMap<UserId, QString> authusernames;
 QMap<UserId, QString> PostgreSqlStorage::getAllAuthUserNames()
 {
     QMap<UserId, QString> authusernames;
index 5322a09..e9fc874 100644 (file)
@@ -108,7 +108,13 @@ public slots:
     bool logMessage(Message &msg) override;
     bool logMessages(MessageList &msgs) override;
     QList<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) override;
     bool logMessage(Message &msg) override;
     bool logMessages(MessageList &msgs) override;
     QList<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) override;
+    QList<Message> requestMsgsFiltered(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1,
+                                       int limit = -1, Message::Types type = Message::Types{-1},
+                                       Message::Flags flags = Message::Flags{-1}) override;
     QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) override;
     QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) override;
+    QList<Message> requestAllMsgsFiltered(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1,
+                                          Message::Types type = Message::Types{-1},
+                                          Message::Flags flags = Message::Flags{-1}) override;
 
     /* Sysident handling */
     QMap<UserId, QString> getAllAuthUserNames() override;
 
     /* Sysident handling */
     QMap<UserId, QString> getAllAuthUserNames() override;
index 96de7f6..c90d472 100644 (file)
     <file>./SQL/PostgreSQL/select_internaluser.sql</file>
     <file>./SQL/PostgreSQL/select_messagesAll.sql</file>
     <file>./SQL/PostgreSQL/select_messagesAllNew.sql</file>
     <file>./SQL/PostgreSQL/select_internaluser.sql</file>
     <file>./SQL/PostgreSQL/select_messagesAll.sql</file>
     <file>./SQL/PostgreSQL/select_messagesAllNew.sql</file>
+    <file>./SQL/PostgreSQL/select_messagesAllNew_filtered.sql</file>
+    <file>./SQL/PostgreSQL/select_messagesAll_filtered.sql</file>
     <file>./SQL/PostgreSQL/select_messagesNewerThan.sql</file>
     <file>./SQL/PostgreSQL/select_messagesNewerThan.sql</file>
+    <file>./SQL/PostgreSQL/select_messagesNewerThan_filtered.sql</file>
     <file>./SQL/PostgreSQL/select_messagesNewestK.sql</file>
     <file>./SQL/PostgreSQL/select_messagesNewestK.sql</file>
+    <file>./SQL/PostgreSQL/select_messagesNewestK_filtered.sql</file>
     <file>./SQL/PostgreSQL/select_messagesRange.sql</file>
     <file>./SQL/PostgreSQL/select_messagesRange.sql</file>
+    <file>./SQL/PostgreSQL/select_messagesRange_filtered.sql</file>
     <file>./SQL/PostgreSQL/select_networkExists.sql</file>
     <file>./SQL/PostgreSQL/select_network_awaymsg.sql</file>
     <file>./SQL/PostgreSQL/select_network_usermode.sql</file>
     <file>./SQL/PostgreSQL/select_networkExists.sql</file>
     <file>./SQL/PostgreSQL/select_network_awaymsg.sql</file>
     <file>./SQL/PostgreSQL/select_network_usermode.sql</file>
     <file>./SQL/SQLite/select_internaluser.sql</file>
     <file>./SQL/SQLite/select_messagesAll.sql</file>
     <file>./SQL/SQLite/select_messagesAllNew.sql</file>
     <file>./SQL/SQLite/select_internaluser.sql</file>
     <file>./SQL/SQLite/select_messagesAll.sql</file>
     <file>./SQL/SQLite/select_messagesAllNew.sql</file>
+    <file>./SQL/SQLite/select_messagesAllNew_filtered.sql</file>
+    <file>./SQL/SQLite/select_messagesAll_filtered.sql</file>
     <file>./SQL/SQLite/select_messagesNewerThan.sql</file>
     <file>./SQL/SQLite/select_messagesNewerThan.sql</file>
+    <file>./SQL/SQLite/select_messagesNewerThan_filtered.sql</file>
     <file>./SQL/SQLite/select_messagesNewestK.sql</file>
     <file>./SQL/SQLite/select_messagesNewestK.sql</file>
+    <file>./SQL/SQLite/select_messagesNewestK_filtered.sql</file>
     <file>./SQL/SQLite/select_messagesRange.sql</file>
     <file>./SQL/SQLite/select_messagesRange.sql</file>
+    <file>./SQL/SQLite/select_messagesRange_filtered.sql</file>
     <file>./SQL/SQLite/select_networkExists.sql</file>
     <file>./SQL/SQLite/select_network_awaymsg.sql</file>
     <file>./SQL/SQLite/select_network_usermode.sql</file>
     <file>./SQL/SQLite/select_networkExists.sql</file>
     <file>./SQL/SQLite/select_network_awaymsg.sql</file>
     <file>./SQL/SQLite/select_network_usermode.sql</file>
index 1e1b798..5139d38 100644 (file)
@@ -1895,6 +1895,82 @@ QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId
 }
 
 
 }
 
 
+QList<Message> SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
+{
+    QList<Message> messagelist;
+
+    QSqlDatabase db = logDb();
+    db.transaction();
+
+    bool error = false;
+    BufferInfo bufferInfo;
+    {
+        // code dupication from getBufferInfo:
+        // this is due to the impossibility of nesting transactions and recursive locking
+        QSqlQuery bufferInfoQuery(db);
+        bufferInfoQuery.prepare(queryString("select_buffer_by_id"));
+        bufferInfoQuery.bindValue(":userid", user.toInt());
+        bufferInfoQuery.bindValue(":bufferid", bufferId.toInt());
+
+        lockForRead();
+        safeExec(bufferInfoQuery);
+        error = !watchQuery(bufferInfoQuery) || !bufferInfoQuery.first();
+        if (!error) {
+            bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), 0, bufferInfoQuery.value(4).toString());
+            error = !bufferInfo.isValid();
+        }
+    }
+    if (error) {
+        db.rollback();
+        unlock();
+        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(":firstmsg", first.toInt());
+        }
+        else {
+            query.prepare(queryString("select_messagesRange_filtered"));
+            query.bindValue(":lastmsg", last.toInt());
+            query.bindValue(":firstmsg", first.toInt());
+        }
+        query.bindValue(":bufferid", bufferId.toInt());
+        query.bindValue(":limit", limit);
+        int typeRaw = type;
+        query.bindValue(":type", typeRaw);
+        int flagsRaw = flags;
+        query.bindValue(":flags", flagsRaw);
+
+        safeExec(query);
+        watchQuery(query);
+
+        while (query.next()) {
+            Message msg(QDateTime::fromTime_t(query.value(1).toInt()),
+                        bufferInfo,
+                        (Message::Type)query.value(2).toUInt(),
+                        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).toInt());
+            messagelist << msg;
+        }
+    }
+    db.commit();
+    unlock();
+
+    return messagelist;
+}
+
+
 QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit)
 {
     QList<Message> messagelist;
 QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId last, int limit)
 {
     QList<Message> messagelist;
@@ -1950,6 +2026,64 @@ QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId las
     return messagelist;
 }
 
     return messagelist;
 }
 
+QList<Message> SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, MsgId last, int limit, Message::Types type, Message::Flags flags)
+{
+    QList<Message> messagelist;
+
+    QSqlDatabase db = logDb();
+    db.transaction();
+
+    QHash<BufferId, BufferInfo> bufferInfoHash;
+    {
+        QSqlQuery bufferInfoQuery(db);
+        bufferInfoQuery.prepare(queryString("select_buffers"));
+        bufferInfoQuery.bindValue(":userid", user.toInt());
+
+        lockForRead();
+        safeExec(bufferInfoQuery);
+        watchQuery(bufferInfoQuery);
+        while (bufferInfoQuery.next()) {
+            BufferInfo bufferInfo = BufferInfo(bufferInfoQuery.value(0).toInt(), bufferInfoQuery.value(1).toInt(), (BufferInfo::Type)bufferInfoQuery.value(2).toInt(), bufferInfoQuery.value(3).toInt(), bufferInfoQuery.value(4).toString());
+            bufferInfoHash[bufferInfo.bufferId()] = bufferInfo;
+        }
+
+        QSqlQuery query(db);
+        if (last == -1) {
+            query.prepare(queryString("select_messagesAllNew_filtered"));
+        }
+        else {
+            query.prepare(queryString("select_messagesAll_filtered"));
+            query.bindValue(":lastmsg", last.toInt());
+        }
+        query.bindValue(":userid", user.toInt());
+        query.bindValue(":firstmsg", first.toInt());
+        query.bindValue(":limit", limit);
+        int typeRaw = type;
+        query.bindValue(":type", typeRaw);
+        int flagsRaw = flags;
+        query.bindValue(":flags", flagsRaw);
+        safeExec(query);
+
+        watchQuery(query);
+
+        while (query.next()) {
+            Message msg(QDateTime::fromTime_t(query.value(2).toInt()),
+                        bufferInfoHash[query.value(1).toInt()],
+                        (Message::Type)query.value(3).toUInt(),
+                        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).toInt());
+            messagelist << msg;
+        }
+    }
+    db.commit();
+    unlock();
+    return messagelist;
+}
 
 QMap<UserId, QString> SqliteStorage::getAllAuthUserNames()
 {
 
 QMap<UserId, QString> SqliteStorage::getAllAuthUserNames()
 {
index 367c644..41312f1 100644 (file)
@@ -109,7 +109,13 @@ public slots:
     bool logMessage(Message &msg) override;
     bool logMessages(MessageList &msgs) override;
     QList<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) override;
     bool logMessage(Message &msg) override;
     bool logMessages(MessageList &msgs) override;
     QList<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) override;
+    QList<Message> requestMsgsFiltered(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1,
+                                       int limit = -1, Message::Types type = Message::Types{-1},
+                                       Message::Flags flags = Message::Flags{-1}) override;
     QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) override;
     QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) override;
+    QList<Message> requestAllMsgsFiltered(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1,
+                                          Message::Types type = Message::Types{-1},
+                                          Message::Flags flags = Message::Flags{-1}) override;
 
     /* Sysident handling */
     QMap<UserId, QString> getAllAuthUserNames() override;
 
     /* Sysident handling */
     QMap<UserId, QString> getAllAuthUserNames() override;
index d22372e..7cbc3e3 100644 (file)
@@ -480,6 +480,18 @@ public slots:
      */
     virtual QList<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) = 0;
 
      */
     virtual QList<Message> requestMsgs(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1, int limit = -1) = 0;
 
+    //! Request a certain number messages stored in a given buffer, matching certain filters
+    /** \param buffer   The buffer we request messages from
+     *  \param first    if != -1 return only messages with a MsgId >= first
+     *  \param last     if != -1 return only messages with a MsgId < last
+     *  \param limit    if != -1 limit the returned list to a max of \limit entries
+     *  \param type     The Message::Types that should be returned
+     *  \return The requested list of messages
+     */
+    virtual QList<Message> requestMsgsFiltered(UserId user, BufferId bufferId, MsgId first = -1, MsgId last = -1,
+                                               int limit = -1, Message::Types type = Message::Types{-1},
+                                               Message::Flags flags = Message::Flags{-1}) = 0;
+
     //! Request a certain number of messages across all buffers
     /** \param first    if != -1 return only messages with a MsgId >= first
      *  \param last     if != -1 return only messages with a MsgId < last
     //! Request a certain number of messages across all buffers
     /** \param first    if != -1 return only messages with a MsgId >= first
      *  \param last     if != -1 return only messages with a MsgId < last
@@ -488,6 +500,17 @@ public slots:
      */
     virtual QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) = 0;
 
      */
     virtual QList<Message> requestAllMsgs(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1) = 0;
 
+    //! Request a certain number of messages across all buffers, matching certain filters
+    /** \param first    if != -1 return only messages with a MsgId >= first
+     *  \param last     if != -1 return only messages with a MsgId < last
+     *  \param limit    Max amount of messages
+     *  \param type     The Message::Types that should be returned
+     *  \return The requested list of messages
+     */
+    virtual QList<Message> requestAllMsgsFiltered(UserId user, MsgId first = -1, MsgId last = -1, int limit = -1,
+                                                  Message::Types type = Message::Types{-1},
+                                                  Message::Flags flags = Message::Flags{-1}) = 0;
+
     //! Fetch all authusernames
     /** \return      Map of all current UserIds to permitted idents
      */
     //! Fetch all authusernames
     /** \return      Map of all current UserIds to permitted idents
      */