Skip to content

Commit d1631e4

Browse files
author
Andrey Lebedev
committed
mysql backend passes all tests (at last!)
1 parent 4d4a6e6 commit d1631e4

File tree

3 files changed

+126
-22
lines changed

3 files changed

+126
-22
lines changed

roundup/backends/back_mysql.py

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1+
#
2+
# Copyright (c) 2003 Martynas Sklyzmantas, Andrey Lebedev
3+
#
4+
# This module is free software, and you may redistribute it and/or modify
5+
# under the same terms as Python, so long as this copyright message and
6+
# disclaimer are retained in their original form.
7+
#
8+
# Mysql backend for roundup
9+
#
10+
111
from roundup.backends.rdbms_common import *
12+
from roundup.backends import rdbms_common
213
import MySQLdb
314
from MySQLdb.constants import ER
415

@@ -13,14 +24,17 @@ def open_connection(self):
1324
raise DatabaseError, message
1425

1526
self.cursor = self.conn.cursor()
27+
# start transaction
28+
self.sql("SET AUTOCOMMIT=0")
29+
self.sql("BEGIN")
1630
try:
1731
self.database_schema = self.load_dbschema()
1832
except MySQLdb.ProgrammingError, message:
1933
if message[0] != ER.NO_SUCH_TABLE:
2034
raise DatabaseError, message
2135
self.database_schema = {}
22-
self.cursor.execute("CREATE TABLE schema (schema TEXT)")
23-
self.cursor.execute("CREATE TABLE ids (name varchar(255), num INT)")
36+
self.sql("CREATE TABLE schema (schema TEXT) TYPE=BDB")
37+
self.sql("CREATE TABLE ids (name varchar(255), num INT) TYPE=BDB")
2438

2539
def close(self):
2640
try:
@@ -43,7 +57,10 @@ def save_dbschema(self, schema):
4357

4458
def load_dbschema(self):
4559
self.cursor.execute('SELECT schema FROM schema')
46-
return eval(self.cursor.fetchone()[0])
60+
schema = self.cursor.fetchone()
61+
if schema:
62+
return eval(schema[0])
63+
return None
4764

4865
def save_journal(self, classname, cols, nodeid, journaldate,
4966
journaltag, action, params):
@@ -74,7 +91,7 @@ def create_class_table(self, spec):
7491
cols.append('id')
7592
cols.append('__retired__')
7693
scols = ',' . join(['`%s` VARCHAR(255)'%x for x in cols])
77-
sql = 'CREATE TABLE `_%s` (%s)'%(spec.classname, scols)
94+
sql = 'CREATE TABLE `_%s` (%s) TYPE=BDB'%(spec.classname, scols)
7895
if __debug__:
7996
print >>hyperdb.DEBUG, 'create_class', (self, sql)
8097
self.cursor.execute(sql)
@@ -83,16 +100,91 @@ def create_class_table(self, spec):
83100
def create_journal_table(self, spec):
84101
cols = ',' . join(['`%s` VARCHAR(255)'%x
85102
for x in 'nodeid date tag action params' . split()])
86-
sql = 'CREATE TABLE `%s__journal` (%s)'%(spec.classname, cols)
103+
sql = 'CREATE TABLE `%s__journal` (%s) TYPE=BDB'%(spec.classname, cols)
87104
if __debug__:
88105
print >>hyperdb.DEBUG, 'create_class', (self, sql)
89106
self.cursor.execute(sql)
90107

91108
def create_multilink_table(self, spec, ml):
92109
sql = '''CREATE TABLE `%s_%s` (linkid VARCHAR(255),
93-
nodeid VARCHAR(255))'''%(spec.classname, ml)
110+
nodeid VARCHAR(255)) TYPE=BDB'''%(spec.classname, ml)
94111
if __debug__:
95112
print >>hyperdb.DEBUG, 'create_class', (self, sql)
96113
self.cursor.execute(sql)
97114

115+
class MysqlClass:
116+
def find(self, **propspec):
117+
'''Get the ids of nodes in this class which link to the given nodes.
118+
119+
Since MySQL < 4.0.0 does not support unions, so we overrideg this
120+
method without using this keyword
121+
122+
'''
123+
if __debug__:
124+
print >>hyperdb.DEBUG, 'find', (self, propspec)
125+
126+
# shortcut
127+
if not propspec:
128+
return []
129+
130+
# validate the args
131+
props = self.getprops()
132+
propspec = propspec.items()
133+
for propname, nodeids in propspec:
134+
# check the prop is OK
135+
prop = props[propname]
136+
if not isinstance(prop, Link) and not isinstance(prop, Multilink):
137+
raise TypeError, "'%s' not a Link/Multilink property"%propname
138+
139+
# first, links
140+
l = []
141+
where = []
142+
allvalues = ()
143+
a = self.db.arg
144+
for prop, values in propspec:
145+
if not isinstance(props[prop], hyperdb.Link):
146+
continue
147+
if type(values) is type(''):
148+
allvalues += (values,)
149+
where.append('_%s = %s'%(prop, a))
150+
else:
151+
allvalues += tuple(values.keys())
152+
where.append('_%s in (%s)'%(prop, ','.join([a]*len(values))))
153+
tables = []
154+
if where:
155+
self.db.sql('select id as nodeid from _%s where %s' % (self.classname, ' and '.join(where)), allvalues)
156+
l += [x[0] for x in self.db.sql_fetchall()]
157+
158+
# now multilinks
159+
for prop, values in propspec:
160+
vals = ()
161+
if not isinstance(props[prop], hyperdb.Multilink):
162+
continue
163+
if type(values) is type(''):
164+
vals = (values,)
165+
s = a
166+
else:
167+
vals = tuple(values.keys())
168+
s = ','.join([a]*len(values))
169+
query = 'select nodeid from %s_%s where linkid in (%s)'%(
170+
self.classname, prop, s)
171+
self.db.sql(query, vals)
172+
l += [x[0] for x in self.db.sql_fetchall()]
173+
if __debug__:
174+
print >>hyperdb.DEBUG, 'find ... ', l
175+
176+
# Remove duplicated ids
177+
d = {}
178+
for k in l:
179+
d[k] = 1
180+
return d.keys()
181+
182+
return l
183+
184+
class Class(MysqlClass, rdbms_common.Class):
185+
pass
186+
class IssueClass(MysqlClass, rdbms_common.IssueClass):
187+
pass
188+
class FileClass(MysqlClass, rdbms_common.FileClass):
189+
pass
98190

roundup/backends/rdbms_common.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: rdbms_common.py,v 1.30 2003-02-06 05:43:47 richard Exp $
1+
# $Id: rdbms_common.py,v 1.31 2003-02-08 15:31:28 kedder Exp $
22
''' Relational database (SQL) backend common code.
33
44
Basics:
@@ -738,6 +738,8 @@ def unserialise(self, classname, node):
738738
p = password.Password()
739739
p.unpack(v)
740740
d[k] = p
741+
elif (isinstance(prop, Boolean) or isinstance(prop, Number)) and v is not None:
742+
d[k]=float(v)
741743
else:
742744
d[k] = v
743745
return d

test/test_db.py

Lines changed: 25 additions & 15 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: test_db.py,v 1.68 2003-01-20 23:03:41 richard Exp $
18+
# $Id: test_db.py,v 1.69 2003-02-08 15:31:28 kedder Exp $
1919

2020
import unittest, os, shutil, time
2121

@@ -732,7 +732,14 @@ def setUp(self):
732732
config.MYSQL_DATABASE = ('localhost', 'rounduptest', 'rounduptest',
733733
'rounduptest')
734734
os.makedirs(config.DATABASE + '/files')
735+
# open database for cleaning
735736
self.db = mysql.Database(config, 'admin')
737+
self.db.sql("DROP DATABASE %s" % config.MYSQL_DATABASE[1])
738+
self.db.sql("CREATE DATABASE %s" % config.MYSQL_DATABASE[1])
739+
self.db.close()
740+
# open database for testing
741+
self.db = mysql.Database(config, 'admin')
742+
736743
setupSchema(self.db, 1, mysql)
737744

738745
class mysqlReadOnlyDBTestCase(anydbmReadOnlyDBTestCase):
@@ -744,13 +751,15 @@ def setUp(self):
744751
config.MYSQL_DATABASE = ('localhost', 'rounduptest', 'rounduptest',
745752
'rounduptest')
746753
os.makedirs(config.DATABASE + '/files')
747-
db = mysql.Database(config, 'admin')
748-
setupSchema(db, 1, mysql)
749-
db.close()
750-
self.db = sqlite.Database(config)
754+
# open database for cleaning
755+
self.db = mysql.Database(config, 'admin')
756+
self.db.sql("DROP DATABASE %s" % config.MYSQL_DATABASE[1])
757+
self.db.sql("CREATE DATABASE %s" % config.MYSQL_DATABASE[1])
758+
self.db.close()
759+
# open database for testing
760+
self.db = mysql.Database(config)
751761
setupSchema(self.db, 0, mysql)
752762

753-
754763
class sqliteDBTestCase(anydbmDBTestCase):
755764
def setUp(self):
756765
from roundup.backends import sqlite
@@ -846,19 +855,20 @@ def setUp(self):
846855
setupSchema(self.db, 0, metakit)
847856

848857
def suite():
849-
l = [
850-
unittest.makeSuite(anydbmDBTestCase, 'test'),
851-
unittest.makeSuite(anydbmReadOnlyDBTestCase, 'test')
852-
]
858+
l = []
859+
# l = [
860+
# unittest.makeSuite(anydbmDBTestCase, 'test'),
861+
# unittest.makeSuite(anydbmReadOnlyDBTestCase, 'test')
862+
# ]
853863
# return unittest.TestSuite(l)
854864

855865
from roundup import backends
856866
p = []
857-
# if hasattr(backends, 'mysql'):
858-
# p.append('mysql')
859-
# l.append(unittest.makeSuite(mysqlDBTestCase, 'test'))
860-
# l.append(unittest.makeSuite(mysqlReadOnlyDBTestCase, 'test'))
861-
# return unittest.TestSuite(l)
867+
if hasattr(backends, 'mysql'):
868+
p.append('mysql')
869+
l.append(unittest.makeSuite(mysqlDBTestCase, 'test'))
870+
l.append(unittest.makeSuite(mysqlReadOnlyDBTestCase, 'test'))
871+
#return unittest.TestSuite(l)
862872

863873
if hasattr(backends, 'gadfly'):
864874
p.append('gadfly')

0 commit comments

Comments
 (0)