Skip to content

Commit 3b1271e

Browse files
author
Richard Jones
committed
MySQL migration of old backend database to new, typed database complete.
1 parent 5cf65e9 commit 3b1271e

File tree

5 files changed

+157
-79
lines changed

5 files changed

+157
-79
lines changed

demo.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# Copyright (c) 2003 Richard Jones ([email protected])
44
#
5-
# $Id: demo.py,v 1.7 2003-11-06 14:24:57 jlgijsbers Exp $
5+
# $Id: demo.py,v 1.8 2004-03-24 03:07:51 richard Exp $
66

77
import sys, os, string, re, urlparse
88
import shutil, socket, errno, BaseHTTPServer
@@ -21,7 +21,7 @@ def install_demo(home):
2121
except os.error, error:
2222
if error.errno != errno.ENOENT:
2323
raise
24-
init.write_select_db(home, 'anydbm')
24+
init.write_select_db(home, 'mysql')
2525

2626
# figure basic params for server
2727
hostname = socket.gethostname()
@@ -49,6 +49,13 @@ def install_demo(home):
4949
s = f.read().replace('http://tracker.example/cgi-bin/roundup.cgi/bugs/',
5050
url)
5151
f.close()
52+
s = s + """
53+
MYSQL_DBHOST = 'localhost'
54+
MYSQL_DBUSER = 'rounduptest'
55+
MYSQL_DBPASSWORD = 'rounduptest'
56+
MYSQL_DBNAME = 'rounduptest'
57+
MYSQL_DATABASE = (MYSQL_DBHOST, MYSQL_DBUSER, MYSQL_DBPASSWORD, MYSQL_DBNAME)
58+
"""
5259
f = open(os.path.join(home, 'config.py'), 'w')
5360
f.write(s)
5461
f.close()

roundup/backends/back_mysql.py

Lines changed: 112 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -191,83 +191,142 @@ def create_version_2_tables(self):
191191
self.cursor.execute(sql, ('__textids', 1))
192192

193193
def add_actor_column(self):
194-
''' While we're adding the actor column, we need to update the
194+
'''While we're adding the actor column, we need to update the
195195
tables to have the correct datatypes.'''
196-
assert 0, 'FINISH ME!'
197-
198-
for spec in self.classes.values():
199-
new_has = spec.properties.has_key
200-
new_spec = spec.schema()
201-
new_spec[1].sort()
202-
old_spec[1].sort()
203-
if not force and new_spec == old_spec:
204-
# no changes
205-
return 0
206-
207-
if __debug__:
208-
print >>hyperdb.DEBUG, 'update_class FIRING'
209-
210-
# detect multilinks that have been removed, and drop their table
211-
old_has = {}
212-
for name,prop in old_spec[1]:
213-
old_has[name] = 1
214-
if new_has(name) or not isinstance(prop, hyperdb.Multilink):
196+
for klass in self.classes.values():
197+
cn = klass.classname
198+
properties = klass.getprops()
199+
old_spec = self.database_schema['tables'][cn]
200+
201+
execute = self.cursor.execute
202+
203+
# figure the non-Multilink properties to copy over
204+
propnames = ['activity', 'creation', 'creator']
205+
206+
# figure actions based on data type
207+
for name, s_prop in old_spec[1]:
208+
# s_prop is a repr() string of a hyperdb type object
209+
if s_prop.find('Multilink') == -1:
210+
if properties.has_key(name):
211+
propnames.append(name)
215212
continue
216-
# it's a multilink, and it's been removed - drop the old
217-
# table. First drop indexes.
218-
self.drop_multilink_table_indexes(spec.classname, ml)
219-
sql = 'drop table %s_%s'%(spec.classname, prop)
213+
tn = '%s_%s'%(cn, name)
214+
215+
if properties.has_key(name):
216+
# grabe the current values
217+
sql = 'select linkid, nodeid from %s'%tn
218+
if __debug__:
219+
print >>hyperdb.DEBUG, 'migration', (self, sql)
220+
execute(sql)
221+
rows = self.cursor.fetchall()
222+
223+
# drop the old table
224+
self.drop_multilink_table_indexes(cn, name)
225+
sql = 'drop table %s'%tn
220226
if __debug__:
221-
print >>hyperdb.DEBUG, 'update_class', (self, sql)
222-
self.cursor.execute(sql)
223-
old_has = old_has.has_key
227+
print >>hyperdb.DEBUG, 'migration', (self, sql)
228+
execute(sql)
224229

225-
# now figure how we populate the new table
226-
if adding_actor:
227-
fetch = ['_activity', '_creation', '_creator']
228-
else:
229-
fetch = ['_actor', '_activity', '_creation', '_creator']
230-
properties = spec.getprops()
231-
for propname,x in new_spec[1]:
232-
prop = properties[propname]
233-
if isinstance(prop, hyperdb.Multilink):
234-
if force or not old_has(propname):
235-
# we need to create the new table
236-
self.create_multilink_table(spec, propname)
237-
elif old_has(propname):
238-
# we copy this col over from the old table
239-
fetch.append('_'+propname)
230+
if properties.has_key(name):
231+
# re-create and populate the new table
232+
self.create_multilink_table(klass, name)
233+
sql = '''insert into %s (linkid, nodeid) values
234+
(%s, %s)'''%(tn, self.arg, self.arg)
235+
for linkid, nodeid in rows:
236+
execute(sql, (int(linkid), int(nodeid)))
237+
238+
# figure the column names to fetch
239+
fetch = ['_%s'%name for name in propnames]
240240

241241
# select the data out of the old table
242242
fetch.append('id')
243243
fetch.append('__retired__')
244244
fetchcols = ','.join(fetch)
245-
cn = spec.classname
246245
sql = 'select %s from _%s'%(fetchcols, cn)
247246
if __debug__:
248-
print >>hyperdb.DEBUG, 'update_class', (self, sql)
247+
print >>hyperdb.DEBUG, 'migration', (self, sql)
249248
self.cursor.execute(sql)
250-
olddata = self.cursor.fetchall()
251249

252-
# TODO: update all the other index dropping code
250+
# unserialise the old data
251+
olddata = []
252+
propnames = propnames + ['id', '__retired__']
253+
for entry in self.cursor.fetchall():
254+
l = []
255+
olddata.append(l)
256+
for i in range(len(propnames)):
257+
name = propnames[i]
258+
v = entry[i]
259+
260+
if name in ('id', '__retired__'):
261+
l.append(int(v))
262+
continue
263+
prop = properties[name]
264+
if isinstance(prop, Date) and v is not None:
265+
v = date.Date(v)
266+
elif isinstance(prop, Interval) and v is not None:
267+
v = date.Interval(v)
268+
elif isinstance(prop, Password) and v is not None:
269+
v = password.Password(encrypted=v)
270+
elif (isinstance(prop, Boolean) or
271+
isinstance(prop, Number)) and v is not None:
272+
v = float(v)
273+
274+
# convert to new MySQL data type
275+
prop = properties[name]
276+
if v is not None:
277+
v = self.hyperdb_to_sql_value[prop.__class__](v)
278+
l.append(v)
279+
253280
self.drop_class_table_indexes(cn, old_spec[0])
254281

255282
# drop the old table
256-
self.cursor.execute('drop table _%s'%cn)
283+
execute('drop table _%s'%cn)
257284

258285
# create the new table
259-
self.create_class_table(spec)
286+
self.create_class_table(klass)
260287

261-
# do the insert of the old data - the new columns will have
262-
# NULL values
288+
# do the insert of the old data
263289
args = ','.join([self.arg for x in fetch])
264290
sql = 'insert into _%s (%s) values (%s)'%(cn, fetchcols, args)
265291
if __debug__:
266-
print >>hyperdb.DEBUG, 'update_class', (self, sql, olddata[0])
292+
print >>hyperdb.DEBUG, 'migration', (self, sql)
267293
for entry in olddata:
268-
self.cursor.execute(sql, tuple(entry))
294+
if __debug__:
295+
print >>hyperdb.DEBUG, '... data', entry
296+
execute(sql, tuple(entry))
269297

270-
return 1
298+
# now load up the old journal data
299+
cols = ','.join('nodeid date tag action params'.split())
300+
sql = 'select %s from %s__journal'%(cols, cn)
301+
if __debug__:
302+
print >>hyperdb.DEBUG, 'migration', (self, sql)
303+
execute(sql)
304+
305+
olddata = []
306+
for nodeid, journaldate, journaltag, action, params in \
307+
self.cursor.fetchall():
308+
nodeid = int(nodeid)
309+
journaldate = date.Date(journaldate)
310+
params = eval(params)
311+
olddata.append((nodeid, journaldate, journaltag, action,
312+
params))
313+
314+
# drop journal table and indexes
315+
self.drop_journal_table_indexes(cn)
316+
sql = 'drop table %s__journal'%cn
317+
if __debug__:
318+
print >>hyperdb.DEBUG, 'migration', (self, sql)
319+
execute(sql)
320+
321+
# re-create journal table
322+
self.create_journal_table(klass)
323+
for nodeid, journaldate, journaltag, action, params in olddata:
324+
self.save_journal(cn, cols, nodeid, journaldate,
325+
journaltag, action, params)
326+
327+
# make sure the normal schema update code doesn't try to
328+
# change things
329+
self.database_schema['tables'][cn] = klass.schema()
271330

272331
def __repr__(self):
273332
return '<myroundsql 0x%x>'%id(self)

roundup/backends/rdbms_common.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: rdbms_common.py,v 1.84 2004-03-22 07:45:39 richard Exp $
1+
# $Id: rdbms_common.py,v 1.85 2004-03-24 03:07:52 richard Exp $
22
''' Relational database (SQL) backend common code.
33
44
Basics:
@@ -200,11 +200,16 @@ def upgrade_db(self):
200200
return 0
201201

202202
if version == 1:
203+
# change the schema structure
204+
self.database_schema = {'tables': self.database_schema}
205+
206+
# version 1 didn't have the actor column (note that in
207+
# MySQL this will also transition the tables to typed columns)
208+
self.add_actor_column()
209+
203210
# version 1 doesn't have the OTK, session and indexing in the
204211
# database
205212
self.create_version_2_tables()
206-
# version 1 also didn't have the actor column
207-
self.add_actor_column()
208213

209214
self.database_schema['version'] = self.current_db_version
210215
return 1
@@ -236,10 +241,10 @@ def determine_columns(self, properties):
236241
instance of a hyperdb "type" _or_ a string repr of that type.
237242
'''
238243
cols = [
239-
('_actor', 'INTEGER'),
240-
('_activity', 'DATE'),
241-
('_creator', 'INTEGER'),
242-
('_creation', 'DATE')
244+
('_actor', self.hyperdb_to_sql_datatypes[hyperdb.Link]),
245+
('_activity', self.hyperdb_to_sql_datatypes[hyperdb.Date]),
246+
('_creator', self.hyperdb_to_sql_datatypes[hyperdb.Link]),
247+
('_creation', self.hyperdb_to_sql_datatypes[hyperdb.Date]),
243248
]
244249
mls = []
245250
# add the multilinks separately
@@ -338,8 +343,8 @@ def update_class(self, spec, old_spec, force=0):
338343
return 1
339344

340345
def create_class_table(self, spec):
341-
''' create the class table for the given spec
342-
'''
346+
'''Create the class table for the given Class "spec". Creates the
347+
indexes too.'''
343348
cols, mls = self.determine_columns(spec.properties.items())
344349

345350
# add on our special columns
@@ -459,14 +464,14 @@ def create_multilink_table(self, spec, ml):
459464
def create_multilink_table_indexes(self, spec, ml):
460465
# create index on linkid
461466
index_sql = 'create index %s_%s_l_idx on %s_%s(linkid)'%(
462-
spec.classname, ml, spec.classname, ml)
467+
spec.classname, ml, spec.classname, ml)
463468
if __debug__:
464469
print >>hyperdb.DEBUG, 'create_index', (self, index_sql)
465470
self.cursor.execute(index_sql)
466471

467472
# create index on nodeid
468473
index_sql = 'create index %s_%s_n_idx on %s_%s(nodeid)'%(
469-
spec.classname, ml, spec.classname, ml)
474+
spec.classname, ml, spec.classname, ml)
470475
if __debug__:
471476
print >>hyperdb.DEBUG, 'create_index', (self, index_sql)
472477
self.cursor.execute(index_sql)
@@ -752,7 +757,7 @@ def setnode(self, classname, nodeid, values, multilink_changes):
752757

753758
sql_to_hyperdb_value = {
754759
hyperdb.String : str,
755-
hyperdb.Date : date.Date,
760+
hyperdb.Date : lambda x:date.Date(str(x).replace(' ', '.')),
756761
# hyperdb.Link : int, # XXX numeric ids
757762
hyperdb.Link : str,
758763
hyperdb.Interval : date.Interval,
@@ -932,7 +937,7 @@ def save_journal(self, classname, cols, nodeid, journaldate,
932937
sql = 'insert into %s__journal (%s) values (%s,%s,%s,%s,%s)'%(
933938
classname, cols, a, a, a, a, a)
934939
if __debug__:
935-
print >>hyperdb.DEBUG, 'addjournal', (self, sql, entry)
940+
print >>hyperdb.DEBUG, 'save_journal', (self, sql, entry)
936941
self.cursor.execute(sql, entry)
937942

938943
def load_journal(self, classname, cols, nodeid):

roundup/cgi/templating.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ def lookupKeys(linkcl, key, ids, num_re=re.compile('-?\d+')):
301301
l = []
302302
for entry in ids:
303303
if num_re.match(entry):
304-
l.append(cl.get(entry, key))
304+
l.append(linkcl.get(entry, key))
305305
else:
306306
l.append(entry)
307307
return l

0 commit comments

Comments
 (0)