diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e6ff0cd0..98c6dace 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2509,48 +2509,42 @@ class MyForm(settingsmixin.SMainWindow): # self.rerenderInboxToLabels() def on_action_MarkAllRead(self): - def partialUpdate(folder, msgids): - if len(msgids) == 0: - return 0 - if folder == 'sent': - return sqlExecute( - "UPDATE sent SET read = 1 WHERE ackdata IN(%s) AND read=0" %(",".join("?"*len(msgids))), *msgids) - else: - return sqlExecute( - "UPDATE inbox SET read = 1 WHERE msgid IN(%s) AND read=0" %(",".join("?"*len(msgids))), *msgids) - - if QtGui.QMessageBox.question(self, "Marking all messages as read?", _translate("MainWindow", "Are you sure you would like to mark all messages read?"), QMessageBox.Yes|QMessageBox.No) != QMessageBox.Yes: + if QtGui.QMessageBox.question( + self, "Marking all messages as read?", + _translate( + "MainWindow", + "Are you sure you would like to mark all messages read?" + ), QMessageBox.Yes | QMessageBox.No) != QMessageBox.Yes: return addressAtCurrentRow = self.getCurrentAccount() tableWidget = self.getCurrentMessagelist() - if tableWidget.rowCount() == 0: + idCount = tableWidget.rowCount() + if idCount == 0: return - msgids = [] - font = QFont() font.setBold(False) - markread = 0 - - for i in range(0, tableWidget.rowCount()): + msgids = [] + for i in range(0, idCount): msgids.append(str(tableWidget.item( i, 3).data(Qt.UserRole).toPyObject())) tableWidget.item(i, 0).setUnread(False) tableWidget.item(i, 1).setUnread(False) tableWidget.item(i, 2).setUnread(False) tableWidget.item(i, 3).setFont(font) - # sqlite default limit, unfortunately getting/setting isn't exposed to python - if i % 999 == 999: - markread += partialUpdate(self.getCurrentFolder(), msgids) - msgids = [] - if len(msgids) > 0: - markread += partialUpdate(self.getCurrentFolder(), msgids) + markread = sqlExecuteChunked( + "UPDATE %s SET read = 1 WHERE %s IN({0}) AND read=0" % ( + ('sent', 'ackdata') if self.getCurrentFolder() == 'sent' + else ('inbox', 'msgid') + ), idCount, *msgids + ) if markread > 0: - self.propagateUnreadCount(addressAtCurrentRow, self.getCurrentFolder(), None, 0) + self.propagateUnreadCount( + addressAtCurrentRow, self.getCurrentFolder(), None, 0) def click_NewAddressDialog(self): addresses = [] @@ -2790,9 +2784,13 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.item(currentRow, 1).setUnread(True) tableWidget.item(currentRow, 2).setUnread(True) tableWidget.item(currentRow, 3).setFont(font) - #sqlite requires the exact number of ?s to prevent injection - rowcount = sqlExecute('''UPDATE inbox SET read=0 WHERE msgid IN (%s) AND read=1''' % ( - "?," * len(inventoryHashesToMarkUnread))[:-1], *inventoryHashesToMarkUnread) + # for 1081 + idCount = len(inventoryHashesToMarkUnread) + rowcount = sqlExecuteChunked( + '''UPDATE inbox SET read=0 WHERE msgid IN ({0}) AND read=1''', + idCount, *inventoryHashesToMarkUnread + ) + if rowcount == 1: # performance optimisation self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), self.getCurrentFolder()) diff --git a/src/helper_sql.py b/src/helper_sql.py index 7410202b..fec67bef 100644 --- a/src/helper_sql.py +++ b/src/helper_sql.py @@ -21,8 +21,10 @@ def sqlQuery(sqlStatement, *args): return queryreturn + def sqlExecuteChunked(sqlStatement, idCount, *args): - #SQLITE_MAX_VARIABLE_NUMBER, unfortunately getting/setting isn't exposed to python + # SQLITE_MAX_VARIABLE_NUMBER, + # unfortunately getting/setting isn't exposed to python sqlExecuteChunked.chunkSize = 999 if idCount == 0 or idCount > len(args): @@ -30,15 +32,26 @@ def sqlExecuteChunked(sqlStatement, idCount, *args): totalRowCount = 0 with sqlLock: - for i in range(len(args)-idCount, len(args), sqlExecuteChunked.chunkSize - (len(args)-idCount)): - sqlSubmitQueue.put(sqlStatement) + for i in range( + len(args) - idCount, len(args), + sqlExecuteChunked.chunkSize - (len(args) - idCount) + ): + chunk_slice = args[ + i:i+sqlExecuteChunked.chunkSize - (len(args) - idCount) + ] + sqlSubmitQueue.put( + sqlStatement.format(','.join('?' * len(chunk_slice))) + ) # first static args, and then iterative chunk - sqlSubmitQueue.put(args[0:len(args)-idCount] + args[i:i+sqlExecuteChunked.chunkSize - (len(args)-idCount)]) + sqlSubmitQueue.put( + args[0:len(args)-idCount] + chunk_slice + ) retVal = sqlReturnQueue.get() totalRowCount += retVal[1] sqlSubmitQueue.put('commit') return totalRowCount + def sqlExecute(sqlStatement, *args): sqlLock.acquire() sqlSubmitQueue.put(sqlStatement)