drop named sql arguments

This commit is contained in:
Damien Elmes 2020-03-02 20:50:17 +10:00
parent c8b9afac0c
commit f4d4078537
7 changed files with 53 additions and 68 deletions

View file

@ -2,8 +2,8 @@
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
# fixme: lossy utf8 handling # fixme: lossy utf8 handling
# fixme: progress
import os
import time import time
from sqlite3 import Cursor from sqlite3 import Cursor
from sqlite3 import dbapi2 as sqlite from sqlite3 import dbapi2 as sqlite
@ -16,19 +16,13 @@ class DBProxy:
self._path = path self._path = path
self.mod = False self.mod = False
def execute(self, sql: str, *a, **ka) -> Cursor: def execute(self, sql: str, *args) -> Cursor:
s = sql.strip().lower() s = sql.strip().lower()
# mark modified? # mark modified?
for stmt in "insert", "update", "delete": for stmt in "insert", "update", "delete":
if s.startswith(stmt): if s.startswith(stmt):
self.mod = True self.mod = True
t = time.time() res = self._db.execute(sql, args)
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)
return res return res
def executemany(self, sql: str, l: Any) -> None: def executemany(self, sql: str, l: Any) -> None:
@ -47,26 +41,25 @@ class DBProxy:
def rollback(self) -> None: def rollback(self) -> None:
self._db.rollback() self._db.rollback()
def scalar(self, *a, **kw) -> Any: def scalar(self, sql: str, *args) -> Any:
res = self.execute(*a, **kw).fetchone() res = self.execute(sql, *args).fetchone()
if res: if res:
return res[0] return res[0]
return None return None
def all(self, *a, **kw) -> List: def all(self, sql: str, *args) -> List:
return self.execute(*a, **kw).fetchall() return self.execute(sql, *args).fetchall()
def first(self, *a, **kw) -> Any: def first(self, sql: str, *args) -> Any:
c = self.execute(*a, **kw) c = self.execute(sql, *args)
res = c.fetchone() res = c.fetchone()
c.close() c.close()
return res return res
def list(self, *a, **kw) -> List: def list(self, sql: str, *args) -> List:
return [x[0] for x in self.execute(*a, **kw)] return [x[0] for x in self.execute(sql, *args)]
def close(self) -> None: def close(self) -> None:
self._db.text_factory = None
self._db.close() self._db.close()
def __enter__(self) -> "DBProxy": def __enter__(self) -> "DBProxy":
@ -79,9 +72,6 @@ class DBProxy:
def totalChanges(self) -> Any: def totalChanges(self) -> Any:
return self._db.total_changes return self._db.total_changes
def interrupt(self) -> None:
self._db.interrupt()
def setAutocommit(self, autocommit: bool) -> None: def setAutocommit(self, autocommit: bool) -> None:
if autocommit: if autocommit:
self._db.isolation_level = None self._db.isolation_level = None

View file

@ -286,10 +286,10 @@ and due <= ? limit %d"""
self._lrnQueue = self.col.db.all( self._lrnQueue = self.col.db.all(
f""" f"""
select due, id from cards where 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""" limit %d"""
% (self._deckLimit(), self.reportLimit), % (self._deckLimit(), self.reportLimit),
lim=self.dayCutoff, self.dayCutoff,
) )
# as it arrives sorted by did first, we need to sort it # as it arrives sorted by did first, we need to sort it
self._lrnQueue.sort() self._lrnQueue.sort()

View file

@ -545,10 +545,10 @@ select count() from cards where did in %s and queue = {QUEUE_TYPE_PREVIEW}
self._lrnQueue = self.col.db.all( self._lrnQueue = self.col.db.all(
f""" f"""
select due, id from cards where 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""" limit %d"""
% (self._deckLimit(), self.reportLimit), % (self._deckLimit(), self.reportLimit),
lim=cutoff, cutoff,
) )
# as it arrives sorted by did first, we need to sort it # as it arrives sorted by did first, we need to sort it
self._lrnQueue.sort() self._lrnQueue.sort()

View file

@ -58,7 +58,7 @@ class CardStats:
self.addLine(_("Reviews"), "%d" % c.reps) self.addLine(_("Reviews"), "%d" % c.reps)
self.addLine(_("Lapses"), "%d" % c.lapses) self.addLine(_("Lapses"), "%d" % c.lapses)
(cnt, total) = self.col.db.first( (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: if cnt:
self.addLine(_("Average Time"), self.time(total / float(cnt))) self.addLine(_("Average Time"), self.time(total / float(cnt)))
@ -297,12 +297,12 @@ and due = ?"""
) -> Any: ) -> Any:
lim = "" lim = ""
if start is not None: 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: if end is not None:
lim += " and day < %d" % end lim += " and day < %d" % end
return self.col.db.all( return self.col.db.all(
f""" 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), -- yng
sum(case when ivl >= 21 then 1 else 0 end) -- mtr sum(case when ivl >= 21 then 1 else 0 end) -- mtr
from cards from cards
@ -310,8 +310,8 @@ where did in %s and queue in ({QUEUE_TYPE_REV},{QUEUE_TYPE_DAY_LEARN_RELEARN})
%s %s
group by day order by day""" group by day order by day"""
% (self._limit(), lim), % (self._limit(), lim),
today=self.col.sched.today, self.col.sched.today,
chunk=chunk, chunk,
) )
# Added, reps and time spent # Added, reps and time spent
@ -527,14 +527,13 @@ group by day order by day"""
return self.col.db.all( return self.col.db.all(
""" """
select 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) count(id)
from cards %s from cards %s
group by day order by day""" group by day order by day"""
% lim, % lim,
cut=self.col.sched.dayCutoff, self.col.sched.dayCutoff,
tf=tf, chunk,
chunk=chunk,
) )
def _done(self, num: Optional[int] = 7, chunk: int = 1) -> Any: 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( return self.col.db.all(
f""" f"""
select 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_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), -- yng count
sum(case when type = {REVLOG_REV} and lastIvl >= 21 then 1 else 0 end), -- mtr 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_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_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 -- 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)/?,
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)/?,
sum(case when type = {REVLOG_RELRN} then time/1000.0 else 0 end)/:tf, -- lapse time 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)/:tf -- cram time sum(case when type = {REVLOG_CRAM} then time/1000.0 else 0 end)/? -- cram time
from revlog %s from revlog %s
group by day order by day""" group by day order by day"""
% lim, % lim,
cut=self.col.sched.dayCutoff, self.col.sched.dayCutoff,
tf=tf, chunk,
chunk=chunk, tf,
tf,
tf,
tf,
tf,
) )
def _daysStudied(self) -> Any: def _daysStudied(self) -> Any:
@ -592,11 +595,11 @@ group by day order by day"""
ret = self.col.db.first( ret = self.col.db.first(
""" """
select count(), abs(min(day)) from (select 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 from revlog %s
group by day order by day)""" group by day order by day)"""
% lim, % lim,
cut=self.col.sched.dayCutoff, self.col.sched.dayCutoff,
) )
assert ret assert ret
return ret return ret
@ -655,12 +658,12 @@ group by day order by day)"""
data = [ data = [
self.col.db.all( self.col.db.all(
f""" 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 where did in %s and queue = {QUEUE_TYPE_REV} %s
group by grp group by grp
order by grp""" order by grp"""
% (self._limit(), lim), % (self._limit(), lim),
chunk=chunk, chunk,
) )
] ]
return ( return (
@ -866,14 +869,14 @@ order by thetype, ease"""
return self.col.db.all( return self.col.db.all(
f""" f"""
select 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) / sum(case when ease = 1 then 0 else 1 end) /
cast(count() as float) * 100, cast(count() as float) * 100,
count() count()
from revlog where type in ({REVLOG_LRN},{REVLOG_REV},{REVLOG_RELRN}) %s from revlog where type in ({REVLOG_LRN},{REVLOG_REV},{REVLOG_RELRN}) %s
group by hour having count() > 30 order by hour""" group by hour having count() > 30 order by hour"""
% lim, % lim,
cut=self.col.sched.dayCutoff - (rolloverHour * 3600), self.col.sched.dayCutoff - (rolloverHour * 3600),
) )
# Cards # Cards

View file

@ -110,30 +110,25 @@ class TagManager:
else: else:
l = "tags " l = "tags "
fn = self.remFromStr 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( res = self.col.db.all(
"select id, tags from notes where id in %s and (%s)" % (ids2str(ids), lim), "select id, tags from notes where id in %s and (%s)" % (ids2str(ids), lim),
**dict( *["%% %s %%" % y.replace("*", "%") for x, y in enumerate(newTags)],
[
("_%d" % x, "%% %s %%" % y.replace("*", "%"))
for x, y in enumerate(newTags)
]
),
) )
# update tags # update tags
nids = [] nids = []
def fix(row): def fix(row):
nids.append(row[0]) nids.append(row[0])
return { return [
"id": row[0], fn(tags, row[1]),
"t": fn(tags, row[1]), intTime(),
"n": intTime(), self.col.usn(),
"u": self.col.usn(), row[0],
} ]
self.col.db.executemany( 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], [fix(row) for row in res],
) )

View file

@ -754,10 +754,7 @@ title="%s" %s>%s</button>""" % (
signal.signal(signal.SIGINT, self.onSigInt) signal.signal(signal.SIGINT, self.onSigInt)
def onSigInt(self, signum, frame): def onSigInt(self, signum, frame):
# interrupt any current transaction and schedule a rollback & quit # schedule a rollback & quit
if self.col:
self.col.db.interrupt()
def quit(): def quit():
self.col.db.rollback() self.col.db.rollback()
self.close() self.close()

View file

@ -35,7 +35,7 @@ class ProgressManager:
"Install a handler in the current DB." "Install a handler in the current DB."
self.lastDbProgress = 0 self.lastDbProgress = 0
self.inDB = False self.inDB = False
#db.set_progress_handler(self._dbProgress, 10000) # db.set_progress_handler(self._dbProgress, 10000)
def _dbProgress(self): def _dbProgress(self):
"Called from SQLite." "Called from SQLite."