core: Migrate SQLite schema to MSec, warn of slow
[quassel.git] / src / core / sqlitestorage.cpp
index 7694021..db174cb 100644 (file)
@@ -1468,7 +1468,7 @@ void SqliteStorage::setBufferLastSeenMsg(UserId user, const BufferId &bufferId,
         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());
 
         lockForWrite();
         safeExec(query);
@@ -1497,7 +1497,7 @@ QHash<BufferId, MsgId> SqliteStorage::bufferLastSeenMsgIds(UserId user)
         error = !watchQuery(query);
         if (!error) {
             while (query.next()) {
-                lastSeenHash[query.value(0).toInt()] = query.value(1).toInt();
+                lastSeenHash[query.value(0).toInt()] = query.value(1).toLongLong();
             }
         }
     }
@@ -1518,7 +1518,7 @@ void SqliteStorage::setBufferMarkerLineMsg(UserId user, const BufferId &bufferId
         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());
 
         lockForWrite();
         safeExec(query);
@@ -1547,7 +1547,7 @@ QHash<BufferId, MsgId> SqliteStorage::bufferMarkerLineMsgIds(UserId user)
         error = !watchQuery(query);
         if (!error) {
             while (query.next()) {
-                markerLineHash[query.value(0).toInt()] = query.value(1).toInt();
+                markerLineHash[query.value(0).toInt()] = query.value(1).toLongLong();
             }
         }
     }
@@ -1617,7 +1617,7 @@ Message::Types SqliteStorage::bufferActivity(BufferId bufferId, MsgId lastSeenMs
         QSqlQuery query(db);
         query.prepare(queryString("select_buffer_bufferactivity"));
         query.bindValue(":bufferid", bufferId.toInt());
-        query.bindValue(":lastseenmsgid", lastSeenMsgId.toInt());
+        query.bindValue(":lastseenmsgid", lastSeenMsgId.toQint64());
 
         lockForRead();
         safeExec(query);
@@ -1734,7 +1734,7 @@ int SqliteStorage::highlightCount(BufferId bufferId, MsgId lastSeenMsgId)
         QSqlQuery query(db);
         query.prepare(queryString("select_buffer_highlightcount"));
         query.bindValue(":bufferid", bufferId.toInt());
-        query.bindValue(":lastseenmsgid", lastSeenMsgId.toInt());
+        query.bindValue(":lastseenmsgid", lastSeenMsgId.toQint64());
 
         lockForRead();
         safeExec(query);
@@ -1756,8 +1756,9 @@ bool SqliteStorage::logMessage(Message &msg)
     {
         QSqlQuery logMessageQuery(db);
         logMessageQuery.prepare(queryString("insert_message"));
-
-        logMessageQuery.bindValue(":time", msg.timestamp().toTime_t());
+        // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
+        // seconds.  This nets us more precision as well as simplifying 64-bit time.
+        logMessageQuery.bindValue(":time", msg.timestamp().toMSecsSinceEpoch());
         logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt());
         logMessageQuery.bindValue(":type", msg.type());
         logMessageQuery.bindValue(":flags", (int)msg.flags());
@@ -1787,7 +1788,7 @@ bool SqliteStorage::logMessage(Message &msg)
             }
         }
         if (!error) {
-            MsgId msgId = logMessageQuery.lastInsertId().toInt();
+            MsgId msgId = logMessageQuery.lastInsertId().toLongLong();
             if (msgId.isValid()) {
                 msg.setMsgId(msgId);
             }
@@ -1839,8 +1840,9 @@ bool SqliteStorage::logMessages(MessageList &msgs)
         logMessageQuery.prepare(queryString("insert_message"));
         for (int i = 0; i < msgs.count(); i++) {
             Message &msg = msgs[i];
-
-            logMessageQuery.bindValue(":time", msg.timestamp().toTime_t());
+            // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
+            // seconds.  This nets us more precision as well as simplifying 64-bit time.
+            logMessageQuery.bindValue(":time", msg.timestamp().toMSecsSinceEpoch());
             logMessageQuery.bindValue(":bufferid", msg.bufferInfo().bufferId().toInt());
             logMessageQuery.bindValue(":type", msg.type());
             logMessageQuery.bindValue(":flags", (int)msg.flags());
@@ -1856,7 +1858,7 @@ bool SqliteStorage::logMessages(MessageList &msgs)
                 break;
             }
             else {
-                msg.setMsgId(logMessageQuery.lastInsertId().toInt());
+                msg.setMsgId(logMessageQuery.lastInsertId().toLongLong());
             }
         }
     }
@@ -1887,7 +1889,7 @@ QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId
     bool error = false;
     BufferInfo bufferInfo;
     {
-        // code dupication from getBufferInfo:
+        // code duplication from getBufferInfo:
         // this is due to the impossibility of nesting transactions and recursive locking
         QSqlQuery bufferInfoQuery(db);
         bufferInfoQuery.prepare(queryString("select_buffer_by_id"));
@@ -1915,12 +1917,12 @@ QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId
         }
         else if (last == -1) {
             query.prepare(queryString("select_messagesNewerThan"));
-            query.bindValue(":firstmsg", first.toInt());
+            query.bindValue(":firstmsg", first.toQint64());
         }
         else {
             query.prepare(queryString("select_messagesRange"));
-            query.bindValue(":lastmsg", last.toInt());
-            query.bindValue(":firstmsg", first.toInt());
+            query.bindValue(":lastmsg", last.toQint64());
+            query.bindValue(":firstmsg", first.toQint64());
         }
         query.bindValue(":bufferid", bufferId.toInt());
         query.bindValue(":limit", limit);
@@ -1929,16 +1931,19 @@ QList<Message> SqliteStorage::requestMsgs(UserId user, BufferId bufferId, MsgId
         watchQuery(query);
 
         while (query.next()) {
-            Message msg(QDateTime::fromTime_t(query.value(1).toInt()),
+            Message msg(
+                // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
+                // seconds.  This nets us more precision as well as simplifying 64-bit time.
+                QDateTime::fromMSecsSinceEpoch(query.value(1).toLongLong()),
                 bufferInfo,
-                (Message::Type)query.value(2).toUInt(),
+                (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).toUInt());
-            msg.setMsgId(query.value(0).toInt());
+                (Message::Flags)query.value(3).toInt());
+            msg.setMsgId(query.value(0).toLongLong());
             messagelist << msg;
         }
     }
@@ -1987,12 +1992,12 @@ QList<Message> SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId
         }
         else if (last == -1) {
             query.prepare(queryString("select_messagesNewerThan_filtered"));
-            query.bindValue(":firstmsg", first.toInt());
+            query.bindValue(":firstmsg", first.toQint64());
         }
         else {
             query.prepare(queryString("select_messagesRange_filtered"));
-            query.bindValue(":lastmsg", last.toInt());
-            query.bindValue(":firstmsg", first.toInt());
+            query.bindValue(":lastmsg", last.toQint64());
+            query.bindValue(":firstmsg", first.toQint64());
         }
         query.bindValue(":bufferid", bufferId.toInt());
         query.bindValue(":limit", limit);
@@ -2005,16 +2010,20 @@ QList<Message> SqliteStorage::requestMsgsFiltered(UserId user, BufferId bufferId
         watchQuery(query);
 
         while (query.next()) {
-            Message msg(QDateTime::fromTime_t(query.value(1).toInt()),
+            Message msg(
+                        // As of SQLite schema version 31, timestamps are stored in milliseconds
+                        // instead of seconds.  This nets us more precision as well as simplifying
+                        // 64-bit time.
+                        QDateTime::fromMSecsSinceEpoch(query.value(1).toLongLong()),
                         bufferInfo,
-                        (Message::Type)query.value(2).toUInt(),
+                        (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).toInt());
+            msg.setMsgId(query.value(0).toLongLong());
             messagelist << msg;
         }
     }
@@ -2052,26 +2061,29 @@ QList<Message> SqliteStorage::requestAllMsgs(UserId user, MsgId first, MsgId las
         }
         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());
         query.bindValue(":limit", limit);
         safeExec(query);
 
         watchQuery(query);
 
         while (query.next()) {
-            Message msg(QDateTime::fromTime_t(query.value(2).toInt()),
+            Message msg(
+                // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
+                // seconds.  This nets us more precision as well as simplifying 64-bit time.
+                QDateTime::fromMSecsSinceEpoch(query.value(2).toLongLong()),
                 bufferInfoHash[query.value(1).toInt()],
-                (Message::Type)query.value(3).toUInt(),
+                (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).toUInt());
-            msg.setMsgId(query.value(0).toInt());
+                (Message::Flags)query.value(4).toInt());
+            msg.setMsgId(query.value(0).toLongLong());
             messagelist << msg;
         }
     }
@@ -2107,10 +2119,10 @@ QList<Message> SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, M
         }
         else {
             query.prepare(queryString("select_messagesAll_filtered"));
-            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());
         query.bindValue(":limit", limit);
         int typeRaw = type;
         query.bindValue(":type", typeRaw);
@@ -2121,16 +2133,20 @@ QList<Message> SqliteStorage::requestAllMsgsFiltered(UserId user, MsgId first, M
         watchQuery(query);
 
         while (query.next()) {
-            Message msg(QDateTime::fromTime_t(query.value(2).toInt()),
+            Message msg(
+                        // As of SQLite schema version 31, timestamps are stored in milliseconds
+                        // instead of seconds.  This nets us more precision as well as simplifying
+                        // 64-bit time.
+                        QDateTime::fromMSecsSinceEpoch(query.value(2).toLongLong()),
                         bufferInfoHash[query.value(1).toInt()],
-                        (Message::Type)query.value(3).toUInt(),
+                        (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).toInt());
+            msg.setMsgId(query.value(0).toLongLong());
             messagelist << msg;
         }
     }
@@ -2234,7 +2250,7 @@ void SqliteMigrationReader::setMaxId(MigrationObject mo)
     }
     QSqlQuery query = logDb().exec(queryString);
     query.first();
-    _maxId = query.value(0).toInt();
+    _maxId = query.value(0).toLongLong();
 }
 
 
@@ -2315,7 +2331,7 @@ bool SqliteMigrationReader::readMo(IdentityMO &identity)
     identity.autoAwayReasonEnabled = value(11).toInt() == 1 ? true : false;
     identity.detachAwayEnabled = value(12).toInt() == 1 ? true : false;
     identity.detachAwayReason = value(13).toString();
-    identity.detchAwayReasonEnabled = value(14).toInt() == 1 ? true : false;
+    identity.detachAwayReasonEnabled = value(14).toInt() == 1 ? true : false;
     identity.ident = value(15).toString();
     identity.kickReason = value(16).toString();
     identity.partReason = value(17).toString();
@@ -2389,9 +2405,9 @@ bool SqliteMigrationReader::readMo(BufferMO &buffer)
     buffer.buffername = value(4).toString();
     buffer.buffercname = value(5).toString();
     buffer.buffertype = value(6).toInt();
-    buffer.lastmsgid = value(7).toInt();
-    buffer.lastseenmsgid = value(8).toInt();
-    buffer.markerlinemsgid = value(9).toInt();
+    buffer.lastmsgid = value(7).toLongLong();
+    buffer.lastseenmsgid = value(8).toLongLong();
+    buffer.markerlinemsgid = value(9).toLongLong();
     buffer.bufferactivity = value(10).toInt();
     buffer.highlightcount = value(11).toInt();
     buffer.key = value(12).toString();
@@ -2417,7 +2433,7 @@ bool SqliteMigrationReader::readMo(SenderMO &sender)
         }
     }
 
-    sender.senderId = value(0).toInt();
+    sender.senderId = value(0).toLongLong();
     sender.sender = value(1).toString();
     sender.realname = value(2).toString();
     sender.avatarurl = value(3).toString();
@@ -2427,11 +2443,11 @@ bool SqliteMigrationReader::readMo(SenderMO &sender)
 
 bool SqliteMigrationReader::readMo(BacklogMO &backlog)
 {
-    int skipSteps = 0;
+    qint64 skipSteps = 0;
     while (!next()) {
         if (backlog.messageid < _maxId) {
-            bindValue(0, backlog.messageid.toInt() + (skipSteps * stepSize()));
-            bindValue(1, backlog.messageid.toInt() + ((skipSteps + 1) * stepSize()));
+            bindValue(0, backlog.messageid.toQint64() + (skipSteps * stepSize()));
+            bindValue(1, backlog.messageid.toQint64() + ((skipSteps + 1) * stepSize()));
             skipSteps++;
             if (!exec())
                 return false;
@@ -2441,12 +2457,14 @@ bool SqliteMigrationReader::readMo(BacklogMO &backlog)
         }
     }
 
-    backlog.messageid = value(0).toInt();
-    backlog.time = QDateTime::fromTime_t(value(1).toInt()).toUTC();
+    backlog.messageid = value(0).toLongLong();
+    // As of SQLite schema version 31, timestamps are stored in milliseconds instead of
+    // seconds.  This nets us more precision as well as simplifying 64-bit time.
+    backlog.time = QDateTime::fromMSecsSinceEpoch(value(1).toLongLong()).toUTC();
     backlog.bufferid = value(2).toInt();
     backlog.type = value(3).toInt();
     backlog.flags = value(4).toInt();
-    backlog.senderid = value(5).toInt();
+    backlog.senderid = value(5).toLongLong();
     backlog.senderprefixes = value(6).toString();
     backlog.message = value(7).toString();
     return true;