Skip to content

Commit 867a665

Browse files
author
Richard Jones
committed
fixed journal marshalling in RDBMS backends [SF#943627]
fixed handling of key values starting with numbers [SF#941363] fixed journal "param" column size in RDBMS backends
1 parent d733a45 commit 867a665

File tree

11 files changed

+87
-41
lines changed

11 files changed

+87
-41
lines changed

CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Fixed:
1010
- fix nested scope bug in rdbms multilink sorting
1111
- re-seed the random number generator for each request
1212
- postgresql backend altered to not use popen (thanks Georges Martin)
13+
- fixed journal marshalling in RDBMS backends (sf bug 943627)
14+
- fixed handling of key values starting with numbers (sf bug 941363)
15+
- fixed journal "param" column size in RDBMS backends
1316

1417

1518
2004-04-18 0.7.0b3

doc/index.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ Fredrik Lundh,
102102
Georges Martin,
103103
Gordon McMillan,
104104
John F Meinel Jr,
105+
Truls E. N�ss,
105106
Patrick Ohly,
106107
Luke Opperman,
107108
Will Partain,

roundup/backends/back_mysql.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class Database(Database):
130130
hyperdb.Password : str,
131131
hyperdb.Boolean : int,
132132
hyperdb.Number : lambda x: x,
133+
hyperdb.Multilink : lambda x: x, # used in journal marshalling
133134
}
134135

135136
def sql_open_connection(self):
@@ -302,13 +303,14 @@ def add_new_columns_v2(self):
302303
print >>hyperdb.DEBUG, '... data', entry
303304
execute(sql, tuple(entry))
304305

305-
# now load up the old journal data
306+
# now load up the old journal data to migrate it
306307
cols = ','.join('nodeid date tag action params'.split())
307308
sql = 'select %s from %s__journal'%(cols, cn)
308309
if __debug__:
309310
print >>hyperdb.DEBUG, 'migration', (self, sql)
310311
execute(sql)
311312

313+
# data conversions
312314
olddata = []
313315
for nodeid, journaldate, journaltag, action, params in \
314316
self.cursor.fetchall():
@@ -394,7 +396,7 @@ def create_journal_table(self, spec):
394396
for x in 'nodeid date tag action params'.split()])
395397
sql = '''create table %s__journal (
396398
nodeid integer, date timestamp, tag varchar(255),
397-
action varchar(255), params varchar(255)) type=%s'''%(
399+
action varchar(255), params text) type=%s'''%(
398400
spec.classname, self.mysql_backend)
399401
if __debug__:
400402
print >>hyperdb.DEBUG, 'create_journal_table', (self, sql)

roundup/backends/back_sqlite.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: back_sqlite.py,v 1.26 2004-04-18 23:05:18 richard Exp $
1+
# $Id: back_sqlite.py,v 1.27 2004-05-02 23:16:05 richard Exp $
22
'''Implements a backend for SQLite.
33
44
See https://pysqlite.sourceforge.net/ for pysqlite info
@@ -36,6 +36,7 @@ class Database(rdbms_common.Database):
3636
hyperdb.Password : str,
3737
hyperdb.Boolean : int,
3838
hyperdb.Number : lambda x: x,
39+
hyperdb.Multilink : lambda x: x, # used in journal marshalling
3940
}
4041
sql_to_hyperdb_value = {
4142
hyperdb.String : str,
@@ -45,6 +46,7 @@ class Database(rdbms_common.Database):
4546
hyperdb.Password : lambda x: password.Password(encrypted=x),
4647
hyperdb.Boolean : int,
4748
hyperdb.Number : rdbms_common._num_cvt,
49+
hyperdb.Multilink : lambda x: x, # used in journal marshalling
4850
}
4951

5052
def sql_open_connection(self):

roundup/backends/rdbms_common.py

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: rdbms_common.py,v 1.95 2004-04-26 20:59:25 richard Exp $
1+
# $Id: rdbms_common.py,v 1.96 2004-05-02 23:16:05 richard Exp $
22
''' Relational database (SQL) backend common code.
33
44
Basics:
@@ -438,7 +438,7 @@ def create_journal_table(self, spec):
438438
for x in 'nodeid date tag action params'.split()])
439439
sql = '''create table %s__journal (
440440
nodeid integer, date timestamp, tag varchar(255),
441-
action varchar(255), params varchar(25))'''%spec.classname
441+
action varchar(255), params text)'''%spec.classname
442442
if __debug__:
443443
print >>hyperdb.DEBUG, 'create_journal_table', (self, sql)
444444
self.cursor.execute(sql)
@@ -619,12 +619,14 @@ def clear(self):
619619

620620
hyperdb_to_sql_value = {
621621
hyperdb.String : str,
622+
# fractional seconds by default
622623
hyperdb.Date : lambda x: x.formal(sep=' ', sec='%.3f'),
623624
hyperdb.Link : int,
624625
hyperdb.Interval : str,
625626
hyperdb.Password : str,
626627
hyperdb.Boolean : lambda x: x and 'TRUE' or 'FALSE',
627628
hyperdb.Number : lambda x: x,
629+
hyperdb.Multilink : lambda x: x, # used in journal marshalling
628630
}
629631
def addnode(self, classname, nodeid, node):
630632
''' Add the specified node to its class's db.
@@ -820,6 +822,7 @@ def setnode(self, classname, nodeid, values, multilink_changes={}):
820822
hyperdb.Password : lambda x: password.Password(encrypted=x),
821823
hyperdb.Boolean : int,
822824
hyperdb.Number : _num_cvt,
825+
hyperdb.Multilink : lambda x: x, # used in journal marshalling
823826
}
824827
def getnode(self, classname, nodeid):
825828
''' Get a node from the database.
@@ -973,6 +976,26 @@ def addjournal(self, classname, nodeid, action, params, creator=None,
973976
if __debug__:
974977
print >>hyperdb.DEBUG, 'addjournal', (nodeid, journaldate,
975978
journaltag, action, params)
979+
980+
# make the journalled data marshallable
981+
if isinstance(params, type({})):
982+
properties = self.getclass(classname).getprops()
983+
for param, value in params.items():
984+
property = properties[param]
985+
cvt = self.hyperdb_to_sql_value[property.__class__]
986+
if isinstance(property, Password):
987+
params[param] = cvt(value)
988+
elif isinstance(property, Date):
989+
params[param] = cvt(value)
990+
elif isinstance(property, Interval):
991+
params[param] = cvt(value)
992+
elif isinstance(property, Boolean):
993+
params[param] = cvt(value)
994+
995+
params = repr(params)
996+
997+
dc = self.hyperdb_to_sql_value[hyperdb.Date]
998+
journaldate = dc(journaldate)
976999

9771000
self.save_journal(classname, cols, nodeid, journaldate,
9781001
journaltag, action, params)
@@ -1001,16 +1024,34 @@ def getjournal(self, classname, nodeid):
10011024
raise IndexError, '%s has no node %s'%(classname, nodeid)
10021025

10031026
cols = ','.join('nodeid date tag action params'.split())
1004-
return self.load_journal(classname, cols, nodeid)
1027+
journal = self.load_journal(classname, cols, nodeid)
1028+
1029+
# now unmarshal the data
1030+
dc = self.sql_to_hyperdb_value[hyperdb.Date]
1031+
res = []
1032+
properties = self.getclass(classname).getprops()
1033+
for nodeid, date_stamp, user, action, params in journal:
1034+
params = eval(params)
1035+
for param, value in params.items():
1036+
property = properties[param]
1037+
cvt = self.sql_to_hyperdb_value[property.__class__]
1038+
if isinstance(property, Password):
1039+
params[param] = cvt(value)
1040+
elif isinstance(property, Date):
1041+
params[param] = cvt(value)
1042+
elif isinstance(property, Interval):
1043+
params[param] = cvt(value)
1044+
elif isinstance(property, Boolean):
1045+
params[param] = cvt(value)
1046+
# XXX numeric ids
1047+
res.append((str(nodeid), dc(date_stamp), user, action, params))
1048+
return res
10051049

10061050
def save_journal(self, classname, cols, nodeid, journaldate,
10071051
journaltag, action, params):
10081052
''' Save the journal entry to the database
10091053
'''
1010-
# make the params db-friendly
1011-
params = repr(params)
1012-
dc = self.hyperdb_to_sql_value[hyperdb.Date]
1013-
entry = (nodeid, dc(journaldate), journaltag, action, params)
1054+
entry = (nodeid, journaldate, journaltag, action, params)
10141055

10151056
# do the insert
10161057
a = self.arg
@@ -1029,13 +1070,7 @@ def load_journal(self, classname, cols, nodeid):
10291070
if __debug__:
10301071
print >>hyperdb.DEBUG, 'load_journal', (self, sql, nodeid)
10311072
self.cursor.execute(sql, (nodeid,))
1032-
res = []
1033-
dc = self.sql_to_hyperdb_value[hyperdb.Date]
1034-
for nodeid, date_stamp, user, action, params in self.cursor.fetchall():
1035-
params = eval(params)
1036-
# XXX numeric ids
1037-
res.append((str(nodeid), dc(date_stamp), user, action, params))
1038-
return res
1073+
return self.cursor.fetchall()
10391074

10401075
def pack(self, pack_before):
10411076
''' Delete all journal entries except "create" before 'pack_before'.

roundup/backends/sessions_rdbms.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#$Id: sessions_rdbms.py,v 1.2 2004-03-31 23:08:39 richard Exp $
1+
#$Id: sessions_rdbms.py,v 1.3 2004-05-02 23:16:05 richard Exp $
22
"""This module defines a very basic store that's used by the CGI interface
33
to store session and one-time-key information.
44
@@ -25,7 +25,7 @@ def exists(self, infoid):
2525
n = self.name
2626
self.cursor.execute('select count(*) from %ss where %s_key=%s'%(n,
2727
n, self.db.arg), (infoid,))
28-
return self.cursor.fetchone()[0]
28+
return int(self.cursor.fetchone()[0])
2929

3030
_marker = []
3131
def get(self, infoid, value, default=_marker):

roundup/cgi/actions.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#$Id: actions.py,v 1.23 2004-04-05 06:13:42 richard Exp $
1+
#$Id: actions.py,v 1.24 2004-05-02 23:16:05 richard Exp $
22

33
import re, cgi, StringIO, urllib, Cookie, time, random
44

@@ -494,7 +494,8 @@ def handle(self):
494494
try:
495495
message = self._editnodes(props, links)
496496
except (ValueError, KeyError, IndexError, exceptions.Reject), message:
497-
self.client.error_message.append(_('Apply Error: ') + str(message))
497+
import traceback;traceback.print_exc()
498+
self.client.error_message.append(_('Edit Error: ') + str(message))
498499
return
499500

500501
# commit now that all the tricky stuff is done
@@ -532,7 +533,6 @@ def handle(self):
532533
try:
533534
# when it hits the None element, it'll set self.nodeid
534535
messages = self._editnodes(props, links)
535-
536536
except (ValueError, KeyError, IndexError, exceptions.Reject), message:
537537
# these errors might just be indicative of user dumbness
538538
self.client.error_message.append(_('Error: ') + str(message))

roundup/cgi/client.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: client.py,v 1.173 2004-04-25 22:19:15 richard Exp $
1+
# $Id: client.py,v 1.174 2004-05-02 23:16:05 richard Exp $
22

33
"""WWW request handler (also used in the stand-alone server).
44
"""
@@ -624,13 +624,13 @@ def set_cookie(self, user):
624624
"""
625625
sessions = self.db.getSessionManager()
626626

627-
# generate a session key
628-
s = '%s%s'%(time.time(), random.random())
629-
print s
630-
self.session = binascii.b2a_base64(s).strip()
631-
while sessions.exists(self.session):
627+
# generate a unique session key
628+
while 1:
632629
s = '%s%s'%(time.time(), random.random())
633-
self.session = binascii.b2a_base64(s).strip()
630+
s = binascii.b2a_base64(s).strip()
631+
if not sessions.exists(s):
632+
break
633+
self.session = s
634634

635635
# clean up the base64
636636
if self.session[-1] == '=':

roundup/cgi/templating.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -289,10 +289,11 @@ def classes(self):
289289
for item in l:
290290
if item == 'user':
291291
m.append(HTMLUserClass(self._client, item))
292-
m.append(HTMLClass(self._client, item))
292+
else:
293+
m.append(HTMLClass(self._client, item))
293294
return m
294295

295-
def lookupIds(db, prop, ids, fail_ok=0, num_re=re.compile('-?\d+')):
296+
def lookupIds(db, prop, ids, fail_ok=0, num_re=re.compile('^-?\d+$')):
296297
''' "fail_ok" should be specified if we wish to pass through bad values
297298
(most likely form values that we wish to represent back to the user)
298299
'''
@@ -310,7 +311,7 @@ def lookupIds(db, prop, ids, fail_ok=0, num_re=re.compile('-?\d+')):
310311
l.append(entry)
311312
return l
312313

313-
def lookupKeys(linkcl, key, ids, num_re=re.compile('-?\d+')):
314+
def lookupKeys(linkcl, key, ids, num_re=re.compile('^-?\d+$')):
314315
''' Look up the "key" values for "ids" list - though some may already
315316
be key values, not ids.
316317
'''
@@ -449,7 +450,7 @@ def designator(self):
449450
''' Return this class' designator (classname) '''
450451
return self._classname
451452

452-
def getItem(self, itemid, num_re=re.compile('-?\d+')):
453+
def getItem(self, itemid, num_re=re.compile('^-?\d+$')):
453454
''' Get an item of this class by its item id.
454455
'''
455456
# make sure we're looking at an itemid
@@ -680,7 +681,7 @@ def journal(self, direction='descending'):
680681
# XXX do this
681682
return []
682683

683-
def history(self, direction='descending', dre=re.compile('\d+')):
684+
def history(self, direction='descending', dre=re.compile('^\d+$')):
684685
self.view_check()
685686

686687
l = ['<table class="history">'
@@ -1523,6 +1524,8 @@ class MultilinkHTMLProperty(HTMLProperty):
15231524
def __init__(self, *args, **kwargs):
15241525
HTMLProperty.__init__(self, *args, **kwargs)
15251526
if self._value:
1527+
self._value = lookupIds(self._db, self._prop, self._value,
1528+
fail_ok=1)
15261529
sortfun = make_sort_function(self._db, self._prop.classname)
15271530
self._value.sort(sortfun)
15281531

roundup/hyperdb.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: hyperdb.py,v 1.96 2004-02-11 23:55:08 richard Exp $
18+
# $Id: hyperdb.py,v 1.97 2004-05-02 23:16:05 richard Exp $
1919

2020
"""Hyperdatabase implementation, especially field types.
2121
"""
@@ -592,7 +592,7 @@ class HyperdbValueError(ValueError):
592592
''' Error converting a raw value into a Hyperdb value '''
593593
pass
594594

595-
def convertLinkValue(db, propname, prop, value, idre=re.compile('\d+')):
595+
def convertLinkValue(db, propname, prop, value, idre=re.compile('^\d+$')):
596596
''' Convert the link value (may be id or key value) to an id value. '''
597597
linkcl = db.classes[prop.classname]
598598
if not idre.match(value):

0 commit comments

Comments
 (0)