Skip to content

Commit 46657aa

Browse files
author
Richard Jones
committed
store Intervals as two columns (and other fixes
1 parent 36a26fd commit 46657aa

File tree

7 files changed

+176
-90
lines changed

7 files changed

+176
-90
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Fixed:
3131
- sqlite backend had stopped using the global lock
3232
- better check for anonymous viewing of user items (sf bug 933510)
3333
- stop Interval from displaying an empty string (sf bug 934022)
34+
- fixed storage of some datatypes in some RDBMS backends
3435

3536

3637
2004-03-27 0.7.0b2

TODO.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
This file contains items that need doing before the next release:
22

3-
. make Intervals store timestamps, not strings
4-
5-
63
Optionally:
74
- have rdbms backends look up the journal for actor if it's not set
85
- migrate to numeric ID values (fixes bug 817217)

roundup/backends/back_mysql.py

Lines changed: 62 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class Database(Database):
126126
# no fractional seconds for MySQL
127127
hyperdb.Date : lambda x: x.formal(sep=' '),
128128
hyperdb.Link : int,
129-
hyperdb.Interval : lambda x: x.serialise(),
129+
hyperdb.Interval : str,
130130
hyperdb.Password : str,
131131
hyperdb.Boolean : int,
132132
hyperdb.Number : lambda x: x,
@@ -190,7 +190,7 @@ def create_version_2_tables(self):
190190
sql = 'insert into ids (name, num) values (%s,%s)'%(self.arg, self.arg)
191191
self.cursor.execute(sql, ('__textids', 1))
192192

193-
def add_actor_column(self):
193+
def add_new_columns_v2(self):
194194
'''While we're adding the actor column, we need to update the
195195
tables to have the correct datatypes.'''
196196
for klass in self.classes.values():
@@ -274,8 +274,15 @@ def add_actor_column(self):
274274
# convert to new MySQL data type
275275
prop = properties[name]
276276
if v is not None:
277-
v = self.hyperdb_to_sql_value[prop.__class__](v)
278-
l.append(v)
277+
e = self.hyperdb_to_sql_value[prop.__class__](v)
278+
l.append(e)
279+
280+
# Intervals store the seconds value too
281+
if isinstance(prop, Interval):
282+
if v is not None:
283+
l.append(v.as_seconds())
284+
else:
285+
l.append(e)
279286

280287
self.drop_class_table_indexes(cn, old_spec[0])
281288

@@ -595,25 +602,24 @@ def filter(self, search_matches, filterspec, sort=(None,None),
595602
# If range creation fails - ignore that search parameter
596603
pass
597604
elif isinstance(propclass, Interval):
605+
# filter using the __<prop>_int__ column
598606
if isinstance(v, type([])):
599607
s = ','.join([a for x in v])
600-
where.append('_%s in (%s)'%(k, s))
601-
args = args + [date.Interval(x).serialise() for x in v]
608+
where.append('__%s_int__ in (%s)'%(k, s))
609+
args = args + [date.Interval(x).as_seconds() for x in v]
602610
else:
603611
try:
604612
# Try to filter on range of intervals
605613
date_rng = Range(v, date.Interval)
606-
if (date_rng.from_value):
607-
where.append('_%s >= %s'%(k, a))
608-
args.append(date_rng.from_value.serialise())
609-
if (date_rng.to_value):
610-
where.append('_%s <= %s'%(k, a))
611-
args.append(date_rng.to_value.serialise())
614+
if date_rng.from_value:
615+
where.append('__%s_int__ >= %s'%(k, a))
616+
args.append(date_rng.from_value.as_seconds())
617+
if date_rng.to_value:
618+
where.append('__%s_int__ <= %s'%(k, a))
619+
args.append(date_rng.to_value.as_seconds())
612620
except ValueError:
613621
# If range creation fails - ignore that search parameter
614622
pass
615-
#where.append('_%s=%s'%(k, a))
616-
#args.append(date.Interval(v).serialise())
617623
else:
618624
if isinstance(v, type([])):
619625
s = ','.join([a for x in v])
@@ -634,49 +640,42 @@ def filter(self, search_matches, filterspec, sort=(None,None),
634640
args = args + v
635641

636642
# "grouping" is just the first-order sorting in the SQL fetch
637-
# can modify it...)
638643
orderby = []
639644
ordercols = []
640-
if group[0] is not None and group[1] is not None:
641-
if group[0] != '-':
642-
orderby.append('_'+group[1])
643-
ordercols.append('_'+group[1])
644-
else:
645-
orderby.append('_'+group[1]+' desc')
646-
ordercols.append('_'+group[1])
647-
648-
# now add in the sorting
649-
group = ''
650-
if sort[0] is not None and sort[1] is not None:
651-
direction, colname = sort
652-
if direction != '-':
653-
if colname == 'id':
654-
orderby.append(colname)
655-
else:
656-
orderby.append('_'+colname)
657-
ordercols.append('_'+colname)
658-
else:
659-
if colname == 'id':
660-
orderby.append(colname+' desc')
661-
ordercols.append(colname)
645+
mlsort = []
646+
for sortby in group, sort:
647+
sdir, prop = sortby
648+
if sdir and prop:
649+
if isinstance(props[prop], Multilink):
650+
mlsort.append(sortby)
651+
continue
652+
elif isinstance(props[prop], Interval):
653+
# use the int column for sorting
654+
o = '__'+prop+'_int__'
655+
ordercols.append(o)
656+
elif prop == 'id':
657+
o = 'id'
662658
else:
663-
orderby.append('_'+colname+' desc')
664-
ordercols.append('_'+colname)
659+
o = '_'+prop
660+
ordercols.append(o)
661+
if sdir == '-':
662+
o += ' desc'
663+
orderby.append(o)
665664

666665
# construct the SQL
667666
frum = ','.join(frum)
668667
if where:
669668
where = ' where ' + (' and '.join(where))
670669
else:
671670
where = ''
672-
cols = ['id']
671+
cols = ['distinct(id)']
673672
if orderby:
674673
cols = cols + ordercols
675674
order = ' order by %s'%(','.join(orderby))
676675
else:
677676
order = ''
678677
cols = ','.join(cols)
679-
sql = 'select %s from %s %s%s%s'%(cols, frum, where, group, order)
678+
sql = 'select %s from %s %s%s'%(cols, frum, where, order)
680679
args = tuple(args)
681680
if __debug__:
682681
print >>hyperdb.DEBUG, 'filter', (self, sql, args)
@@ -685,7 +684,28 @@ def filter(self, search_matches, filterspec, sort=(None,None),
685684

686685
# return the IDs (the first column)
687686
# XXX numeric ids
688-
return [str(row[0]) for row in l]
687+
l = [str(row[0]) for row in l]
688+
689+
if not mlsort:
690+
return l
691+
692+
# ergh. someone wants to sort by a multilink.
693+
r = []
694+
for id in l:
695+
m = []
696+
for ml in mlsort:
697+
m.append(self.get(id, ml[1]))
698+
r.append((id, m))
699+
i = 0
700+
for sortby in mlsort:
701+
def sortfun(a, b, dir=sortby[i]):
702+
if dir == '-':
703+
return cmp(b[1][i], a[1][i])
704+
else:
705+
return cmp(a[1][i], b[1][i])
706+
r.sort(sortfun)
707+
i += 1
708+
return [i[0] for i in r]
689709

690710
class Class(MysqlClass, rdbms_common.Class):
691711
pass

roundup/backends/back_sqlite.py

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: back_sqlite.py,v 1.24 2004-04-07 01:12:26 richard Exp $
1+
# $Id: back_sqlite.py,v 1.25 2004-04-18 05:31:02 richard Exp $
22
'''Implements a backend for SQLite.
33
44
See https://pysqlite.sourceforge.net/ for pysqlite info
@@ -32,16 +32,15 @@ class Database(rdbms_common.Database):
3232
hyperdb.String : str,
3333
hyperdb.Date : lambda x: x.serialise(),
3434
hyperdb.Link : int,
35-
hyperdb.Interval : lambda x: x.serialise(),
35+
hyperdb.Interval : str,
3636
hyperdb.Password : str,
3737
hyperdb.Boolean : int,
3838
hyperdb.Number : lambda x: x,
3939
}
4040
sql_to_hyperdb_value = {
4141
hyperdb.String : str,
4242
hyperdb.Date : lambda x: date.Date(str(x)),
43-
# hyperdb.Link : int, # XXX numeric ids
44-
hyperdb.Link : str,
43+
hyperdb.Link : str, # XXX numeric ids
4544
hyperdb.Interval : date.Interval,
4645
hyperdb.Password : lambda x: password.Password(encrypted=x),
4746
hyperdb.Boolean : int,
@@ -95,17 +94,17 @@ def create_version_2_tables(self):
9594
sql = 'insert into ids (name, num) values (%s,%s)'%(self.arg, self.arg)
9695
self.cursor.execute(sql, ('__textids', 1))
9796

98-
def add_actor_column(self):
97+
def add_new_columns_v2(self):
9998
# update existing tables to have the new actor column
10099
tables = self.database_schema['tables']
101100
for classname, spec in self.classes.items():
102101
if tables.has_key(classname):
103102
dbspec = tables[classname]
104-
self.update_class(spec, dbspec, force=1, adding_actor=1)
103+
self.update_class(spec, dbspec, force=1, adding_v2=1)
105104
# we've updated - don't try again
106105
tables[classname] = spec.schema()
107106

108-
def update_class(self, spec, old_spec, force=0, adding_actor=0):
107+
def update_class(self, spec, old_spec, force=0, adding_v2=0):
109108
''' Determine the differences between the current spec and the
110109
database version of the spec, and update where necessary.
111110
@@ -141,7 +140,7 @@ def update_class(self, spec, old_spec, force=0, adding_actor=0):
141140
old_has = old_has.has_key
142141

143142
# now figure how we populate the new table
144-
if adding_actor:
143+
if adding_v2:
145144
fetch = ['_activity', '_creation', '_creator']
146145
else:
147146
fetch = ['_actor', '_activity', '_creation', '_creator']
@@ -201,14 +200,41 @@ def update_class(self, spec, old_spec, force=0, adding_actor=0):
201200
self.create_class_table(spec)
202201

203202
if olddata:
203+
inscols = []
204+
for propname,x in new_spec[1]:
205+
prop = properties[propname]
206+
if isinstance(prop, hyperdb.Multilink):
207+
continue
208+
elif isinstance(prop, hyperdb.Interval):
209+
inscols.append('_'+propname)
210+
inscols.append('__'+propname+'_int__')
211+
elif old_has(propname):
212+
# we copy this col over from the old table
213+
inscols.append('_'+propname)
214+
204215
# do the insert of the old data - the new columns will have
205216
# NULL values
206-
args = ','.join([self.arg for x in fetch])
207-
sql = 'insert into _%s (%s) values (%s)'%(cn, fetchcols, args)
217+
args = ','.join([self.arg for x in inscols])
218+
cols = ','.join(inscols)
219+
sql = 'insert into _%s (%s) values (%s)'%(cn, cols, args)
208220
if __debug__:
209221
print >>hyperdb.DEBUG, 'update_class', (self, sql, olddata[0])
210222
for entry in olddata:
211-
self.cursor.execute(sql, tuple(entry))
223+
d = []
224+
for name in inscols:
225+
# generate the new value for the Interval int column
226+
if name.endswith('_int__'):
227+
name = name[2:-6]
228+
if entry.has_key(name):
229+
v = hyperdb.Interval(entry[name]).as_seconds()
230+
else:
231+
v = None
232+
elif entry.has_key(name):
233+
v = entry[name]
234+
else:
235+
v = None
236+
d.append(v)
237+
self.cursor.execute(sql, tuple(d))
212238

213239
return 1
214240

0 commit comments

Comments
 (0)