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+
111from roundup .backends .rdbms_common import *
12+ from roundup .backends import rdbms_common
213import MySQLdb
314from 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
0 commit comments