diff --git a/pylib/anki/dbproxy.py b/pylib/anki/dbproxy.py index 153e1effc..8c597c9e2 100644 --- a/pylib/anki/dbproxy.py +++ b/pylib/anki/dbproxy.py @@ -2,8 +2,8 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html # fixme: lossy utf8 handling +# fixme: progress -import os import time from sqlite3 import Cursor from sqlite3 import dbapi2 as sqlite @@ -16,19 +16,13 @@ class DBProxy: self._path = path self.mod = False - def execute(self, sql: str, *a, **ka) -> Cursor: + def execute(self, sql: str, *args) -> Cursor: s = sql.strip().lower() # mark modified? for stmt in "insert", "update", "delete": if s.startswith(stmt): self.mod = True - t = time.time() - if ka: - # execute("...where id = :id", id=5) - res = self._db.execute(sql, ka) - else: - # execute("...where id = ?", 5) - res = self._db.execute(sql, a) + res = self._db.execute(sql, args) return res def executemany(self, sql: str, l: Any) -> None: @@ -47,26 +41,25 @@ class DBProxy: def rollback(self) -> None: self._db.rollback() - def scalar(self, *a, **kw) -> Any: - res = self.execute(*a, **kw).fetchone() + def scalar(self, sql: str, *args) -> Any: + res = self.execute(sql, *args).fetchone() if res: return res[0] return None - def all(self, *a, **kw) -> List: - return self.execute(*a, **kw).fetchall() + def all(self, sql: str, *args) -> List: + return self.execute(sql, *args).fetchall() - def first(self, *a, **kw) -> Any: - c = self.execute(*a, **kw) + def first(self, sql: str, *args) -> Any: + c = self.execute(sql, *args) res = c.fetchone() c.close() return res - def list(self, *a, **kw) -> List: - return [x[0] for x in self.execute(*a, **kw)] + def list(self, sql: str, *args) -> List: + return [x[0] for x in self.execute(sql, *args)] def close(self) -> None: - self._db.text_factory = None self._db.close() def __enter__(self) -> "DBProxy": @@ -79,9 +72,6 @@ class DBProxy: def totalChanges(self) -> Any: return self._db.total_changes - def interrupt(self) -> None: - self._db.interrupt() - def setAutocommit(self, autocommit: bool) -> None: if autocommit: self._db.isolation_level = None diff --git a/pylib/anki/sched.py b/pylib/anki/sched.py index 91d531bb8..982da8b59 100644 --- a/pylib/anki/sched.py +++ b/pylib/anki/sched.py @@ -286,10 +286,10 @@ and due <= ? limit %d""" self._lrnQueue = self.col.db.all( f""" select due, id from cards where -did in %s and queue = {QUEUE_TYPE_LRN} and due < :lim +did in %s and queue = {QUEUE_TYPE_LRN} and due < ? limit %d""" % (self._deckLimit(), self.reportLimit), - lim=self.dayCutoff, + self.dayCutoff, ) # as it arrives sorted by did first, we need to sort it self._lrnQueue.sort() diff --git a/pylib/anki/schedv2.py b/pylib/anki/schedv2.py index 68275a892..d11f7808d 100644 --- a/pylib/anki/schedv2.py +++ b/pylib/anki/schedv2.py @@ -545,10 +545,10 @@ select count() from cards where did in %s and queue = {QUEUE_TYPE_PREVIEW} self._lrnQueue = self.col.db.all( f""" select due, id from cards where -did in %s and queue in ({QUEUE_TYPE_LRN},{QUEUE_TYPE_PREVIEW}) and due < :lim +did in %s and queue in ({QUEUE_TYPE_LRN},{QUEUE_TYPE_PREVIEW}) and due < ? limit %d""" % (self._deckLimit(), self.reportLimit), - lim=cutoff, + cutoff, ) # as it arrives sorted by did first, we need to sort it self._lrnQueue.sort() diff --git a/pylib/anki/stats.py b/pylib/anki/stats.py index c8ffa2c0b..69ab0c415 100644 --- a/pylib/anki/stats.py +++ b/pylib/anki/stats.py @@ -58,7 +58,7 @@ class CardStats: self.addLine(_("Reviews"), "%d" % c.reps) self.addLine(_("Lapses"), "%d" % c.lapses) (cnt, total) = self.col.db.first( - "select count(), sum(time)/1000 from revlog where cid = :id", id=c.id + "select count(), sum(time)/1000 from revlog where cid = ?", c.id ) if cnt: self.addLine(_("Average Time"), self.time(total / float(cnt))) @@ -297,12 +297,12 @@ and due = ?""" ) -> Any: lim = "" if start is not None: - lim += " and due-:today >= %d" % start + lim += " and due-%d >= %d" % (self.col.sched.today, start) if end is not None: lim += " and day < %d" % end return self.col.db.all( f""" -select (due-:today)/:chunk as day, +select (due-?)/? as day, sum(case when ivl < 21 then 1 else 0 end), -- yng sum(case when ivl >= 21 then 1 else 0 end) -- mtr from cards @@ -310,8 +310,8 @@ where did in %s and queue in ({QUEUE_TYPE_REV},{QUEUE_TYPE_DAY_LEARN_RELEARN}) %s group by day order by day""" % (self._limit(), lim), - today=self.col.sched.today, - chunk=chunk, + self.col.sched.today, + chunk, ) # Added, reps and time spent @@ -527,14 +527,13 @@ group by day order by day""" return self.col.db.all( """ select -(cast((id/1000.0 - :cut) / 86400.0 as int))/:chunk as day, +(cast((id/1000.0 - ?) / 86400.0 as int))/? as day, count(id) from cards %s group by day order by day""" % lim, - cut=self.col.sched.dayCutoff, - tf=tf, - chunk=chunk, + self.col.sched.dayCutoff, + chunk, ) def _done(self, num: Optional[int] = 7, chunk: int = 1) -> Any: @@ -557,24 +556,28 @@ group by day order by day""" return self.col.db.all( f""" select -(cast((id/1000.0 - :cut) / 86400.0 as int))/:chunk as day, +(cast((id/1000.0 - ?) / 86400.0 as int))/? as day, sum(case when type = {REVLOG_LRN} then 1 else 0 end), -- lrn count sum(case when type = {REVLOG_REV} and lastIvl < 21 then 1 else 0 end), -- yng count sum(case when type = {REVLOG_REV} and lastIvl >= 21 then 1 else 0 end), -- mtr count sum(case when type = {REVLOG_RELRN} then 1 else 0 end), -- lapse count sum(case when type = {REVLOG_CRAM} then 1 else 0 end), -- cram count -sum(case when type = {REVLOG_LRN} then time/1000.0 else 0 end)/:tf, -- lrn time +sum(case when type = {REVLOG_LRN} then time/1000.0 else 0 end)/?, -- lrn time -- yng + mtr time -sum(case when type = {REVLOG_REV} and lastIvl < 21 then time/1000.0 else 0 end)/:tf, -sum(case when type = {REVLOG_REV} and lastIvl >= 21 then time/1000.0 else 0 end)/:tf, -sum(case when type = {REVLOG_RELRN} then time/1000.0 else 0 end)/:tf, -- lapse time -sum(case when type = {REVLOG_CRAM} then time/1000.0 else 0 end)/:tf -- cram time +sum(case when type = {REVLOG_REV} and lastIvl < 21 then time/1000.0 else 0 end)/?, +sum(case when type = {REVLOG_REV} and lastIvl >= 21 then time/1000.0 else 0 end)/?, +sum(case when type = {REVLOG_RELRN} then time/1000.0 else 0 end)/?, -- lapse time +sum(case when type = {REVLOG_CRAM} then time/1000.0 else 0 end)/? -- cram time from revlog %s group by day order by day""" % lim, - cut=self.col.sched.dayCutoff, - tf=tf, - chunk=chunk, + self.col.sched.dayCutoff, + chunk, + tf, + tf, + tf, + tf, + tf, ) def _daysStudied(self) -> Any: @@ -592,11 +595,11 @@ group by day order by day""" ret = self.col.db.first( """ select count(), abs(min(day)) from (select -(cast((id/1000 - :cut) / 86400.0 as int)+1) as day +(cast((id/1000 - ?) / 86400.0 as int)+1) as day from revlog %s group by day order by day)""" % lim, - cut=self.col.sched.dayCutoff, + self.col.sched.dayCutoff, ) assert ret return ret @@ -655,12 +658,12 @@ group by day order by day)""" data = [ self.col.db.all( f""" -select ivl / :chunk as grp, count() from cards +select ivl / ? as grp, count() from cards where did in %s and queue = {QUEUE_TYPE_REV} %s group by grp order by grp""" % (self._limit(), lim), - chunk=chunk, + chunk, ) ] return ( @@ -866,14 +869,14 @@ order by thetype, ease""" return self.col.db.all( f""" select -23 - ((cast((:cut - id/1000) / 3600.0 as int)) %% 24) as hour, +23 - ((cast((? - id/1000) / 3600.0 as int)) %% 24) as hour, sum(case when ease = 1 then 0 else 1 end) / cast(count() as float) * 100, count() from revlog where type in ({REVLOG_LRN},{REVLOG_REV},{REVLOG_RELRN}) %s group by hour having count() > 30 order by hour""" % lim, - cut=self.col.sched.dayCutoff - (rolloverHour * 3600), + self.col.sched.dayCutoff - (rolloverHour * 3600), ) # Cards diff --git a/pylib/anki/tags.py b/pylib/anki/tags.py index 9f643a1e3..7d9e642b0 100644 --- a/pylib/anki/tags.py +++ b/pylib/anki/tags.py @@ -110,30 +110,25 @@ class TagManager: else: l = "tags " fn = self.remFromStr - lim = " or ".join([l + "like :_%d" % c for c, t in enumerate(newTags)]) + lim = " or ".join(l + "like ?" for x in newTags) res = self.col.db.all( "select id, tags from notes where id in %s and (%s)" % (ids2str(ids), lim), - **dict( - [ - ("_%d" % x, "%% %s %%" % y.replace("*", "%")) - for x, y in enumerate(newTags) - ] - ), + *["%% %s %%" % y.replace("*", "%") for x, y in enumerate(newTags)], ) # update tags nids = [] def fix(row): nids.append(row[0]) - return { - "id": row[0], - "t": fn(tags, row[1]), - "n": intTime(), - "u": self.col.usn(), - } + return [ + fn(tags, row[1]), + intTime(), + self.col.usn(), + row[0], + ] self.col.db.executemany( - "update notes set tags=:t,mod=:n,usn=:u where id = :id", + "update notes set tags=?,mod=?,usn=? where id = ?", [fix(row) for row in res], ) diff --git a/qt/aqt/main.py b/qt/aqt/main.py index 49e418f06..1a2a1473a 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -754,10 +754,7 @@ title="%s" %s>%s""" % ( signal.signal(signal.SIGINT, self.onSigInt) def onSigInt(self, signum, frame): - # interrupt any current transaction and schedule a rollback & quit - if self.col: - self.col.db.interrupt() - + # schedule a rollback & quit def quit(): self.col.db.rollback() self.close() diff --git a/qt/aqt/progress.py b/qt/aqt/progress.py index e16697614..e072bcb81 100644 --- a/qt/aqt/progress.py +++ b/qt/aqt/progress.py @@ -35,7 +35,7 @@ class ProgressManager: "Install a handler in the current DB." self.lastDbProgress = 0 self.inDB = False - #db.set_progress_handler(self._dbProgress, 10000) + # db.set_progress_handler(self._dbProgress, 10000) def _dbProgress(self): "Called from SQLite."