From: kedder Date: Sat, 8 Feb 2003 15:31:28 +0000 (+0000) Subject: mysql backend passes all tests (at last!) X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=db502d362680dc0fa36e4f36ed23b9841dcccb71;p=roundup.git mysql backend passes all tests (at last!) git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1493 57a73879-2fb5-44c3-a270-3262357dd7e2 --- diff --git a/roundup/backends/back_mysql.py b/roundup/backends/back_mysql.py index fc7162b..4c9c8af 100644 --- a/roundup/backends/back_mysql.py +++ b/roundup/backends/back_mysql.py @@ -1,4 +1,15 @@ +# +# Copyright (c) 2003 Martynas Sklyzmantas, Andrey Lebedev +# +# This module is free software, and you may redistribute it and/or modify +# under the same terms as Python, so long as this copyright message and +# disclaimer are retained in their original form. +# +# Mysql backend for roundup +# + from roundup.backends.rdbms_common import * +from roundup.backends import rdbms_common import MySQLdb from MySQLdb.constants import ER @@ -13,14 +24,17 @@ class Database(Database): raise DatabaseError, message self.cursor = self.conn.cursor() + # start transaction + self.sql("SET AUTOCOMMIT=0") + self.sql("BEGIN") try: self.database_schema = self.load_dbschema() except MySQLdb.ProgrammingError, message: if message[0] != ER.NO_SUCH_TABLE: raise DatabaseError, message self.database_schema = {} - self.cursor.execute("CREATE TABLE schema (schema TEXT)") - self.cursor.execute("CREATE TABLE ids (name varchar(255), num INT)") + self.sql("CREATE TABLE schema (schema TEXT) TYPE=BDB") + self.sql("CREATE TABLE ids (name varchar(255), num INT) TYPE=BDB") def close(self): try: @@ -43,7 +57,10 @@ class Database(Database): def load_dbschema(self): self.cursor.execute('SELECT schema FROM schema') - return eval(self.cursor.fetchone()[0]) + schema = self.cursor.fetchone() + if schema: + return eval(schema[0]) + return None def save_journal(self, classname, cols, nodeid, journaldate, journaltag, action, params): @@ -74,7 +91,7 @@ class Database(Database): cols.append('id') cols.append('__retired__') scols = ',' . join(['`%s` VARCHAR(255)'%x for x in cols]) - sql = 'CREATE TABLE `_%s` (%s)'%(spec.classname, scols) + sql = 'CREATE TABLE `_%s` (%s) TYPE=BDB'%(spec.classname, scols) if __debug__: print >>hyperdb.DEBUG, 'create_class', (self, sql) self.cursor.execute(sql) @@ -83,16 +100,91 @@ class Database(Database): def create_journal_table(self, spec): cols = ',' . join(['`%s` VARCHAR(255)'%x for x in 'nodeid date tag action params' . split()]) - sql = 'CREATE TABLE `%s__journal` (%s)'%(spec.classname, cols) + sql = 'CREATE TABLE `%s__journal` (%s) TYPE=BDB'%(spec.classname, cols) if __debug__: print >>hyperdb.DEBUG, 'create_class', (self, sql) self.cursor.execute(sql) def create_multilink_table(self, spec, ml): sql = '''CREATE TABLE `%s_%s` (linkid VARCHAR(255), - nodeid VARCHAR(255))'''%(spec.classname, ml) + nodeid VARCHAR(255)) TYPE=BDB'''%(spec.classname, ml) if __debug__: print >>hyperdb.DEBUG, 'create_class', (self, sql) self.cursor.execute(sql) +class MysqlClass: + def find(self, **propspec): + '''Get the ids of nodes in this class which link to the given nodes. + + Since MySQL < 4.0.0 does not support unions, so we overrideg this + method without using this keyword + + ''' + if __debug__: + print >>hyperdb.DEBUG, 'find', (self, propspec) + + # shortcut + if not propspec: + return [] + + # validate the args + props = self.getprops() + propspec = propspec.items() + for propname, nodeids in propspec: + # check the prop is OK + prop = props[propname] + if not isinstance(prop, Link) and not isinstance(prop, Multilink): + raise TypeError, "'%s' not a Link/Multilink property"%propname + + # first, links + l = [] + where = [] + allvalues = () + a = self.db.arg + for prop, values in propspec: + if not isinstance(props[prop], hyperdb.Link): + continue + if type(values) is type(''): + allvalues += (values,) + where.append('_%s = %s'%(prop, a)) + else: + allvalues += tuple(values.keys()) + where.append('_%s in (%s)'%(prop, ','.join([a]*len(values)))) + tables = [] + if where: + self.db.sql('select id as nodeid from _%s where %s' % (self.classname, ' and '.join(where)), allvalues) + l += [x[0] for x in self.db.sql_fetchall()] + + # now multilinks + for prop, values in propspec: + vals = () + if not isinstance(props[prop], hyperdb.Multilink): + continue + if type(values) is type(''): + vals = (values,) + s = a + else: + vals = tuple(values.keys()) + s = ','.join([a]*len(values)) + query = 'select nodeid from %s_%s where linkid in (%s)'%( + self.classname, prop, s) + self.db.sql(query, vals) + l += [x[0] for x in self.db.sql_fetchall()] + if __debug__: + print >>hyperdb.DEBUG, 'find ... ', l + + # Remove duplicated ids + d = {} + for k in l: + d[k] = 1 + return d.keys() + + return l + +class Class(MysqlClass, rdbms_common.Class): + pass +class IssueClass(MysqlClass, rdbms_common.IssueClass): + pass +class FileClass(MysqlClass, rdbms_common.FileClass): + pass diff --git a/roundup/backends/rdbms_common.py b/roundup/backends/rdbms_common.py index 002f5a7..3d41caf 100644 --- a/roundup/backends/rdbms_common.py +++ b/roundup/backends/rdbms_common.py @@ -1,4 +1,4 @@ -# $Id: rdbms_common.py,v 1.30 2003-02-06 05:43:47 richard Exp $ +# $Id: rdbms_common.py,v 1.31 2003-02-08 15:31:28 kedder Exp $ ''' Relational database (SQL) backend common code. Basics: @@ -738,6 +738,8 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): p = password.Password() p.unpack(v) d[k] = p + elif (isinstance(prop, Boolean) or isinstance(prop, Number)) and v is not None: + d[k]=float(v) else: d[k] = v return d diff --git a/test/test_db.py b/test/test_db.py index 7f2a209..5c078bb 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: test_db.py,v 1.68 2003-01-20 23:03:41 richard Exp $ +# $Id: test_db.py,v 1.69 2003-02-08 15:31:28 kedder Exp $ import unittest, os, shutil, time @@ -732,7 +732,14 @@ class mysqlDBTestCase(anydbmDBTestCase): config.MYSQL_DATABASE = ('localhost', 'rounduptest', 'rounduptest', 'rounduptest') os.makedirs(config.DATABASE + '/files') + # open database for cleaning self.db = mysql.Database(config, 'admin') + self.db.sql("DROP DATABASE %s" % config.MYSQL_DATABASE[1]) + self.db.sql("CREATE DATABASE %s" % config.MYSQL_DATABASE[1]) + self.db.close() + # open database for testing + self.db = mysql.Database(config, 'admin') + setupSchema(self.db, 1, mysql) class mysqlReadOnlyDBTestCase(anydbmReadOnlyDBTestCase): @@ -744,13 +751,15 @@ class mysqlReadOnlyDBTestCase(anydbmReadOnlyDBTestCase): config.MYSQL_DATABASE = ('localhost', 'rounduptest', 'rounduptest', 'rounduptest') os.makedirs(config.DATABASE + '/files') - db = mysql.Database(config, 'admin') - setupSchema(db, 1, mysql) - db.close() - self.db = sqlite.Database(config) + # open database for cleaning + self.db = mysql.Database(config, 'admin') + self.db.sql("DROP DATABASE %s" % config.MYSQL_DATABASE[1]) + self.db.sql("CREATE DATABASE %s" % config.MYSQL_DATABASE[1]) + self.db.close() + # open database for testing + self.db = mysql.Database(config) setupSchema(self.db, 0, mysql) - class sqliteDBTestCase(anydbmDBTestCase): def setUp(self): from roundup.backends import sqlite @@ -846,19 +855,20 @@ class metakitReadOnlyDBTestCase(anydbmReadOnlyDBTestCase): setupSchema(self.db, 0, metakit) def suite(): - l = [ - unittest.makeSuite(anydbmDBTestCase, 'test'), - unittest.makeSuite(anydbmReadOnlyDBTestCase, 'test') - ] + l = [] +# l = [ +# unittest.makeSuite(anydbmDBTestCase, 'test'), +# unittest.makeSuite(anydbmReadOnlyDBTestCase, 'test') +# ] # return unittest.TestSuite(l) from roundup import backends p = [] -# if hasattr(backends, 'mysql'): -# p.append('mysql') -# l.append(unittest.makeSuite(mysqlDBTestCase, 'test')) -# l.append(unittest.makeSuite(mysqlReadOnlyDBTestCase, 'test')) -# return unittest.TestSuite(l) + if hasattr(backends, 'mysql'): + p.append('mysql') + l.append(unittest.makeSuite(mysqlDBTestCase, 'test')) + l.append(unittest.makeSuite(mysqlReadOnlyDBTestCase, 'test')) + #return unittest.TestSuite(l) if hasattr(backends, 'gadfly'): p.append('gadfly')