data/PredictorTrainingReader.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "data/PredictorTrainingReader.h" | ||
| 2 | #include "data/MailCacheSql.h" | ||
| 3 | #include "data/Models.h" | ||
| 4 | |||
| 5 | #include <QDateTime> | ||
| 6 | #include <QSqlError> | ||
| 7 | #include <QSqlQuery> | ||
| 8 | #include <QTimeZone> | ||
| 9 | #include <QVariant> | ||
| 10 | |||
| 11 | 377 | PredictorTrainingReader::TrainingSnapshot PredictorTrainingReader::trainingSnapshot( | |
| 12 | const QString &account, const QString &folder) const { | ||
| 13 | 377 | TrainingSnapshot result; | |
| 14 |
3/3✓ Branch 2 → 3 taken 377 times.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 11 taken 376 times.
|
377 | if (!m_db.isOpen()) { |
| 15 | 1 | result.error = QStringLiteral("Training cache is not open"); return result; | |
| 16 | } | ||
| 17 |
1/1✓ Branch 11 → 12 taken 376 times.
|
376 | QSqlQuery query(m_db); |
| 18 |
1/1✓ Branch 15 → 16 taken 376 times.
|
376 | query.prepare(QStringLiteral( |
| 19 | "SELECT f.id,f.uidvalidity,coalesce(r.revision,'') FROM folders f " | ||
| 20 | "LEFT JOIN training_revisions r ON r.folder_id=f.id WHERE f.account=? AND f.path=?")); | ||
| 21 |
2/2✓ Branch 20 → 21 taken 376 times.
✓ Branch 24 → 25 taken 376 times.
|
376 | query.addBindValue(account); query.addBindValue(folder); |
| 22 |
7/8✓ Branch 26 → 27 taken 376 times.
✓ Branch 27 → 28 taken 376 times.
✗ Branch 27 → 30 not taken.
✓ Branch 28 → 29 taken 376 times.
✓ Branch 29 → 30 taken 1 time.
✓ Branch 29 → 31 taken 375 times.
✓ Branch 32 → 33 taken 1 time.
✓ Branch 32 → 49 taken 375 times.
|
376 | if (!query.exec() || !query.next()) { |
| 23 |
3/8✓ Branch 33 → 34 taken 1 time.
✓ Branch 34 → 35 taken 1 time.
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 38 taken 1 time.
✗ Branch 36 → 37 not taken.
✗ Branch 37 → 41 not taken.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 84 not taken.
|
4 | result.error = query.lastError().isValid() ? query.lastError().text() |
| 24 |
2/6✓ Branch 43 → 44 taken 1 time.
✗ Branch 43 → 45 not taken.
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 1 time.
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 80 not taken.
|
2 | : QStringLiteral("Predictor training mailbox no longer exists"); |
| 25 | 1 | return result; | |
| 26 | } | ||
| 27 |
2/2✓ Branch 49 → 50 taken 375 times.
✓ Branch 50 → 51 taken 375 times.
|
375 | result.folderId = query.value(0).toLongLong(); |
| 28 |
2/2✓ Branch 52 → 53 taken 375 times.
✓ Branch 53 → 54 taken 375 times.
|
375 | result.uidValidity = query.value(1).toUInt(); |
| 29 |
2/2✓ Branch 55 → 56 taken 375 times.
✓ Branch 56 → 57 taken 375 times.
|
375 | result.revision = query.value(2).toString(); |
| 30 | 375 | return result; | |
| 31 | 376 | } | |
| 32 | |||
| 33 | 572 | PredictorTrainingReader::TrainingPage PredictorTrainingReader::trainingPage(const QString &account, | |
| 34 | const QString &folder, | ||
| 35 | qint64 afterUid) const { | ||
| 36 | 572 | TrainingPage result; | |
| 37 |
3/3✓ Branch 2 → 3 taken 572 times.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 11 taken 571 times.
|
572 | if (!m_db.isOpen()) { |
| 38 | 1 | result.error = QStringLiteral("Training cache is not open"); | |
| 39 | 1 | return result; | |
| 40 | } | ||
| 41 |
1/1✓ Branch 11 → 12 taken 571 times.
|
571 | QSqlQuery query(m_db); |
| 42 |
1/1✓ Branch 15 → 16 taken 571 times.
|
571 | query.prepare(QStringLiteral( |
| 43 | "SELECT h.uid, " | ||
| 44 | "CASE WHEN length(CAST(h.from_addr AS BLOB))<=8192 THEN h.from_addr END, " | ||
| 45 | "CASE WHEN length(CAST(h.subject AS BLOB))<=8192 THEN h.subject END, " | ||
| 46 | "CASE WHEN length(CAST(h.to_addr AS BLOB))<=8192 THEN h.to_addr END, " | ||
| 47 | "coalesce(length(CAST(h.from_addr AS BLOB)),0)>8192 OR " | ||
| 48 | "coalesce(length(CAST(h.subject AS BLOB)),0)>8192 OR " | ||
| 49 | "coalesce(length(CAST(h.to_addr AS BLOB)),0)>8192, f.uidvalidity, f.id " | ||
| 50 | "FROM headers h JOIN folders f ON f.id=h.folder_id " | ||
| 51 | "WHERE f.account=? AND f.path=? AND h.uid>? ORDER BY h.uid LIMIT 128")); | ||
| 52 |
1/1✓ Branch 20 → 21 taken 571 times.
|
571 | query.addBindValue(account); |
| 53 |
1/1✓ Branch 24 → 25 taken 571 times.
|
571 | query.addBindValue(folder); |
| 54 |
1/1✓ Branch 28 → 29 taken 571 times.
|
571 | query.addBindValue(afterUid); |
| 55 |
3/3✓ Branch 30 → 31 taken 571 times.
✓ Branch 31 → 32 taken 2 times.
✓ Branch 31 → 38 taken 569 times.
|
571 | if (!query.exec()) { |
| 56 |
2/2✓ Branch 32 → 33 taken 2 times.
✓ Branch 33 → 34 taken 2 times.
|
2 | result.error = query.lastError().text(); |
| 57 | 2 | return result; | |
| 58 | } | ||
| 59 |
3/3✓ Branch 80 → 81 taken 5685 times.
✓ Branch 81 → 39 taken 5118 times.
✓ Branch 81 → 82 taken 567 times.
|
5685 | while (query.next()) { |
| 60 |
4/4✓ Branch 39 → 40 taken 5118 times.
✓ Branch 40 → 41 taken 5118 times.
✓ Branch 42 → 43 taken 2 times.
✓ Branch 42 → 51 taken 5116 times.
|
5118 | if (query.value(4).toBool()) { |
| 61 |
1/1✓ Branch 43 → 44 taken 2 times.
|
2 | result.headers.clear(); |
| 62 | 2 | result.error = QStringLiteral("Predictor header exceeds the 8 KiB field limit"); | |
| 63 | 2 | return result; | |
| 64 | } | ||
| 65 |
2/2✓ Branch 51 → 52 taken 5116 times.
✓ Branch 52 → 53 taken 5116 times.
|
5116 | result.uidValidity = query.value(5).toUInt(); |
| 66 |
2/2✓ Branch 54 → 55 taken 5116 times.
✓ Branch 55 → 56 taken 5116 times.
|
5116 | result.folderId = query.value(6).toLongLong(); |
| 67 | 5116 | MailHeader header; | |
| 68 |
2/2✓ Branch 58 → 59 taken 5116 times.
✓ Branch 59 → 60 taken 5116 times.
|
5116 | header.uid = query.value(0).toLongLong(); |
| 69 |
2/2✓ Branch 61 → 62 taken 5116 times.
✓ Branch 62 → 63 taken 5116 times.
|
5116 | header.from = query.value(1).toString(); |
| 70 |
2/2✓ Branch 66 → 67 taken 5116 times.
✓ Branch 67 → 68 taken 5116 times.
|
5116 | header.subject = query.value(2).toString(); |
| 71 |
2/2✓ Branch 71 → 72 taken 5116 times.
✓ Branch 72 → 73 taken 5116 times.
|
5116 | header.to = query.value(3).toString(); |
| 72 |
1/1✓ Branch 77 → 78 taken 5116 times.
|
5116 | result.headers.append(std::move(header)); |
| 73 | 5116 | } | |
| 74 |
3/4✓ Branch 82 → 83 taken 567 times.
✓ Branch 83 → 84 taken 567 times.
✗ Branch 85 → 86 not taken.
✓ Branch 85 → 93 taken 567 times.
|
567 | if (query.lastError().isValid()) { |
| 75 | ✗ | result.headers.clear(); | |
| 76 | ✗ | result.error = query.lastError().text(); | |
| 77 | } | ||
| 78 | 567 | return result; | |
| 79 | 571 | } | |
| 80 | |||
| 81 | 481 | PredictorTrainingReader::TrainingPage PredictorTrainingReader::trainingHeaders( | |
| 82 | const QString &account, qint64 folderId, const QString &folder, | ||
| 83 | quint32 uidValidity, const QList<qint64> &uids) const { | ||
| 84 | 481 | TrainingPage result; | |
| 85 | 481 | result.uidValidity = uidValidity; | |
| 86 | 481 | result.folderId = folderId; | |
| 87 |
8/9✓ Branch 2 → 3 taken 481 times.
✓ Branch 3 → 4 taken 481 times.
✗ Branch 3 → 8 not taken.
✓ Branch 5 → 6 taken 480 times.
✓ Branch 5 → 8 taken 1 time.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 479 times.
✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 18 taken 479 times.
|
481 | if (!m_db.isOpen() || uids.isEmpty() || uids.size() > 128) { |
| 88 | 2 | result.error = QStringLiteral("Training cache is closed or the UID batch is invalid"); | |
| 89 | 2 | return result; | |
| 90 | } | ||
| 91 | 479 | QStringList placeholders; | |
| 92 |
2/2✓ Branch 37 → 20 taken 3644 times.
✓ Branch 37 → 38 taken 478 times.
|
4122 | for (qint64 uid : uids) { |
| 93 |
2/2✓ Branch 21 → 22 taken 1 time.
✓ Branch 21 → 29 taken 3643 times.
|
3644 | if (uid <= 0) { |
| 94 | 1 | result.error = QStringLiteral("Invalid predictor training UID"); | |
| 95 | 1 | return result; | |
| 96 | } | ||
| 97 |
1/1✓ Branch 32 → 33 taken 3643 times.
|
3643 | placeholders.append(QStringLiteral("?")); |
| 98 | } | ||
| 99 |
1/1✓ Branch 38 → 39 taken 478 times.
|
478 | QSqlQuery query(m_db); |
| 100 |
1/1✓ Branch 47 → 48 taken 478 times.
|
1434 | query.prepare(QStringLiteral( |
| 101 | "SELECT h.uid, " | ||
| 102 | "CASE WHEN length(CAST(h.from_addr AS BLOB))<=8192 THEN h.from_addr END, " | ||
| 103 | "CASE WHEN length(CAST(h.subject AS BLOB))<=8192 THEN h.subject END, " | ||
| 104 | "CASE WHEN length(CAST(h.to_addr AS BLOB))<=8192 THEN h.to_addr END, " | ||
| 105 | "coalesce(length(CAST(h.from_addr AS BLOB)),0)>8192 OR " | ||
| 106 | "coalesce(length(CAST(h.subject AS BLOB)),0)>8192 OR " | ||
| 107 | "coalesce(length(CAST(h.to_addr AS BLOB)),0)>8192, h.is_spam, " | ||
| 108 | // Sprint 105 S105.3.1: the evidence fields, bounded like the rest. | ||
| 109 | "substr(h.cc_addr,1,8192), substr(h.list_id,1,1024), substr(h.message_id,1,1024), " | ||
| 110 | "substr(h.in_reply_to,1,8192), substr(h.ref_ids,1,8192), h.date " | ||
| 111 | "FROM folders f LEFT JOIN headers h ON h.folder_id=f.id AND h.uid IN (%1) " | ||
| 112 | "WHERE f.id=? AND f.account=? AND f.path=? AND f.uidvalidity=? ORDER BY h.uid") | ||
| 113 |
2/2✓ Branch 45 → 46 taken 478 times.
✓ Branch 46 → 47 taken 478 times.
|
956 | .arg(placeholders.join(QLatin1Char(',')))); |
| 114 |
3/3✓ Branch 57 → 58 taken 3643 times.
✓ Branch 61 → 54 taken 3643 times.
✓ Branch 61 → 62 taken 478 times.
|
4121 | for (qint64 uid : uids) query.addBindValue(uid); |
| 115 |
1/1✓ Branch 64 → 65 taken 478 times.
|
478 | query.addBindValue(folderId); |
| 116 |
1/1✓ Branch 68 → 69 taken 478 times.
|
478 | query.addBindValue(account); |
| 117 |
1/1✓ Branch 72 → 73 taken 478 times.
|
478 | query.addBindValue(folder); |
| 118 |
1/1✓ Branch 76 → 77 taken 478 times.
|
478 | query.addBindValue(uidValidity); |
| 119 |
2/3✓ Branch 78 → 79 taken 478 times.
✗ Branch 79 → 80 not taken.
✓ Branch 79 → 86 taken 478 times.
|
478 | if (!query.exec()) { |
| 120 | ✗ | result.error = query.lastError().text(); | |
| 121 | ✗ | return result; | |
| 122 | } | ||
| 123 | 478 | bool identityMatched = false; | |
| 124 |
3/3✓ Branch 173 → 174 taken 3978 times.
✓ Branch 174 → 87 taken 3502 times.
✓ Branch 174 → 175 taken 476 times.
|
3978 | while (query.next()) { |
| 125 | 3502 | identityMatched = true; | |
| 126 |
4/4✓ Branch 87 → 88 taken 3502 times.
✓ Branch 88 → 89 taken 3502 times.
✓ Branch 90 → 91 taken 5 times.
✓ Branch 90 → 92 taken 3497 times.
|
3502 | if (query.value(0).isNull()) continue; // Matching mailbox; requested messages were removed. |
| 127 |
4/4✓ Branch 92 → 93 taken 3497 times.
✓ Branch 93 → 94 taken 3497 times.
✓ Branch 95 → 96 taken 2 times.
✓ Branch 95 → 104 taken 3495 times.
|
3497 | if (query.value(4).toBool()) { |
| 128 |
1/1✓ Branch 96 → 97 taken 2 times.
|
2 | result.headers.clear(); |
| 129 | 2 | result.error = QStringLiteral("Predictor header exceeds the 8 KiB field limit"); | |
| 130 | 2 | return result; | |
| 131 | } | ||
| 132 | 3495 | MailHeader header; | |
| 133 |
2/2✓ Branch 105 → 106 taken 3495 times.
✓ Branch 106 → 107 taken 3495 times.
|
3495 | header.uid = query.value(0).toLongLong(); |
| 134 |
2/2✓ Branch 108 → 109 taken 3495 times.
✓ Branch 109 → 110 taken 3495 times.
|
3495 | header.from = query.value(1).toString(); |
| 135 |
2/2✓ Branch 113 → 114 taken 3495 times.
✓ Branch 114 → 115 taken 3495 times.
|
3495 | header.subject = query.value(2).toString(); |
| 136 |
2/2✓ Branch 118 → 119 taken 3495 times.
✓ Branch 119 → 120 taken 3495 times.
|
3495 | header.to = query.value(3).toString(); |
| 137 | 3495 | header.folderId = folderId; | |
| 138 |
2/2✓ Branch 123 → 124 taken 3495 times.
✓ Branch 124 → 125 taken 3495 times.
|
3495 | header.isSpam = query.value(5).toBool(); |
| 139 |
2/2✓ Branch 126 → 127 taken 3495 times.
✓ Branch 127 → 128 taken 3495 times.
|
3495 | header.cc = query.value(6).toString(); |
| 140 |
2/2✓ Branch 131 → 132 taken 3495 times.
✓ Branch 132 → 133 taken 3495 times.
|
3495 | header.listId = query.value(7).toString(); |
| 141 |
2/2✓ Branch 136 → 137 taken 3495 times.
✓ Branch 137 → 138 taken 3495 times.
|
3495 | header.messageId = query.value(8).toString(); |
| 142 |
3/3✓ Branch 141 → 142 taken 3495 times.
✓ Branch 142 → 143 taken 3495 times.
✓ Branch 143 → 144 taken 3495 times.
|
3495 | header.inReplyToIds = MailCacheSql::decodeThreadIds(query.value(9).toString()); |
| 143 |
3/3✓ Branch 148 → 149 taken 3495 times.
✓ Branch 149 → 150 taken 3495 times.
✓ Branch 150 → 151 taken 3495 times.
|
3495 | header.references = MailCacheSql::decodeThreadIds(query.value(10).toString()); |
| 144 |
4/4✓ Branch 155 → 156 taken 3495 times.
✓ Branch 156 → 157 taken 3495 times.
✓ Branch 158 → 159 taken 636 times.
✓ Branch 158 → 168 taken 2859 times.
|
3495 | if (!query.value(11).isNull()) |
| 145 |
4/4✓ Branch 159 → 160 taken 636 times.
✓ Branch 160 → 161 taken 636 times.
✓ Branch 161 → 162 taken 636 times.
✓ Branch 162 → 163 taken 636 times.
|
636 | header.date = QDateTime::fromSecsSinceEpoch(query.value(11).toLongLong(), QTimeZone::utc()); |
| 146 |
1/1✓ Branch 169 → 170 taken 3495 times.
|
3495 | result.headers.append(std::move(header)); |
| 147 | 3495 | } | |
| 148 |
3/4✓ Branch 175 → 176 taken 476 times.
✓ Branch 176 → 177 taken 476 times.
✗ Branch 178 → 179 not taken.
✓ Branch 178 → 186 taken 476 times.
|
476 | if (query.lastError().isValid()) { |
| 149 | ✗ | result.headers.clear(); | |
| 150 | ✗ | result.error = query.lastError().text(); | |
| 151 |
2/2✓ Branch 186 → 187 taken 13 times.
✓ Branch 186 → 194 taken 463 times.
|
476 | } else if (!identityMatched) { |
| 152 | 13 | result.error = QStringLiteral("Predictor training mailbox identity changed"); | |
| 153 | } | ||
| 154 | 476 | return result; | |
| 155 | 479 | } | |
| 156 | |||
| 157 | 985 | bool PredictorTrainingReader::trainingIdentityCurrent(const QString &account, qint64 folderId, | |
| 158 | const QString &folder, quint32 uidValidity) const { | ||
| 159 |
1/1✓ Branch 2 → 3 taken 985 times.
|
985 | QSqlQuery query(m_db); |
| 160 |
1/1✓ Branch 6 → 7 taken 985 times.
|
985 | query.prepare(QStringLiteral( |
| 161 | "SELECT 1 FROM folders WHERE id=? AND account=? AND path=? AND uidvalidity=?")); | ||
| 162 |
2/2✓ Branch 11 → 12 taken 985 times.
✓ Branch 15 → 16 taken 985 times.
|
985 | query.addBindValue(folderId); query.addBindValue(account); |
| 163 |
2/2✓ Branch 19 → 20 taken 985 times.
✓ Branch 23 → 24 taken 985 times.
|
985 | query.addBindValue(folder); query.addBindValue(uidValidity); |
| 164 |
5/6✓ Branch 25 → 26 taken 985 times.
✓ Branch 26 → 27 taken 985 times.
✗ Branch 26 → 30 not taken.
✓ Branch 27 → 28 taken 985 times.
✓ Branch 28 → 29 taken 984 times.
✓ Branch 28 → 30 taken 1 time.
|
1970 | return query.exec() && query.next(); |
| 165 | 985 | } | |
| 166 |