/[gnue]/gnue-common/src/datasources/drivers/mysql/mysql/Driver.py
ViewVC logotype

Diff of /gnue-common/src/datasources/drivers/mysql/mysql/Driver.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.4 by jcater, Wed Jun 4 23:23:34 2003 UTC revision 1.5 by jcater, Wed Jun 25 23:09:40 2003 UTC
# Line 1  Line 1 
1  #  #
2  # This file is part of GNU Enterprise.  # This file is part of GNU Enterprise.
3  #  #
4  # GNU Enterprise is free software; you can redistribute it  # GNU Enterprise is free software; you can redistribute it
5  # and/or modify it under the terms of the GNU General Public  # and/or modify it under the terms of the GNU General Public
6  # License as published by the Free Software Foundation; either  # License as published by the Free Software Foundation; either
7  # version 2, or (at your option) any later version.  # version 2, or (at your option) any later version.
8  #  #
9  # GNU Enterprise is distributed in the hope that it will be  # GNU Enterprise is distributed in the hope that it will be
10  # useful, but WITHOUT ANY WARRANTY; without even the implied  # useful, but WITHOUT ANY WARRANTY; without even the implied
11  # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  # PURPOSE. See the GNU General Public License for more details.  # PURPOSE. See the GNU General Public License for more details.
13  #  #
14  # You should have received a copy of the GNU General Public  # You should have received a copy of the GNU General Public
15  # License along with program; see the file COPYING. If not,  # License along with program; see the file COPYING. If not,
16  # write to the Free Software Foundation, Inc., 59 Temple Place  # write to the Free Software Foundation, Inc., 59 Temple Place
17  # - Suite 330, Boston, MA 02111-1307, USA.  # - Suite 330, Boston, MA 02111-1307, USA.
18  #  #
19  # Copyright 2000-2003 Free Software Foundation  # Copyright 2000-2003 Free Software Foundation
20  #  #
21  # FILE:  # FILE:
22  # mysql/DBdriver.py  # mysql/DBdriver.py
23  #  #
24  # DESCRIPTION:  # DESCRIPTION:
25  # Driver to provide access to data vi MySQL  # Driver to provide access to data vi MySQL
26  #  #
27  # NOTES:  # NOTES:
28  # Supports transactions if the MySQL server is compiled w/transaction support  # Supports transactions if the MySQL server is compiled w/transaction support
29  # (which it does NOT by default)  # (which it does NOT by default)
30    
31    
32  import string  import string
33  import sys  import sys
34  from gnue.common.datasources import GDataObjects, GConditions  from gnue.common.datasources import GDataObjects, GConditions
35  from gnue.common.apps import GDebug  from gnue.common.apps import GDebug
36  from gnue.common.datasources.drivers.DBSIG2.Driver \  from gnue.common.datasources.drivers.DBSIG2.Driver \
37     import DBSIG_RecordSet, DBSIG_ResultSet, DBSIG_DataObject, \     import DBSIG_RecordSet, DBSIG_ResultSet, DBSIG_DataObject, \
38            DBSIG_DataObject_SQL, DBSIG_DataObject_Object            DBSIG_DataObject_SQL, DBSIG_DataObject_Object
39    
40  try:  try:
41    import MySQLdb    import MySQLdb
42  except ImportError, mesg:  except ImportError, mesg:
43    GDebug.printMesg(1,mesg)    GDebug.printMesg(1,mesg)
44    print "-"*79    print "-"*79
45    print _("\nCould not load MySQLdb.  For MySQL support, please install \n") \    print _("\nCould not load MySQLdb.  For MySQL support, please install \n") \
46        + _("mysql-python 0.9.0 or later from") \        + _("mysql-python 0.9.0 or later from") \
47        + "http://sourceforge.net/projects/mysql-python\n"        + "http://sourceforge.net/projects/mysql-python\n"
48    print _("Error:  %s") % mesg    print _("Error:  %s") % mesg
49    print "-"*79    print "-"*79
50    sys.exit()    sys.exit()
51    
52    
53    
54  class MySQL_RecordSet(DBSIG_RecordSet):  class MySQL_RecordSet(DBSIG_RecordSet):
55    pass    pass
56    
57    
58  class MySQL_ResultSet(DBSIG_ResultSet):  class MySQL_ResultSet(DBSIG_ResultSet):
59    def __init__(self, dataObject, cursor=None, defaultValues={}, masterRecordSet=None):    def __init__(self, dataObject, cursor=None, defaultValues={}, masterRecordSet=None):
60      DBSIG_ResultSet.__init__(self, dataObject, \      DBSIG_ResultSet.__init__(self, dataObject, \
61              cursor, defaultValues, masterRecordSet)              cursor, defaultValues, masterRecordSet)
62      self._recordSetClass = MySQL_RecordSet      self._recordSetClass = MySQL_RecordSet
63    
64      # Compensate for bug in python mysql drivers older than 0.9.2a2      # Compensate for bug in python mysql drivers older than 0.9.2a2
65      if MySQLdb.__version__ >= '0.9.2a2':      if MySQLdb.__version__ >= '0.9.2a2':
66        self.fetchBugFix = self._cursor.fetchmany        self.fetchBugFix = self._cursor.fetchmany
67      else:      else:
68        self.__done = 0        self.__done = 0
69        self.fetchBugFix = self.__mySqlNeedsLotsOfTLC        self.fetchBugFix = self.__mySqlNeedsLotsOfTLC
70    
71        
72    # Compensate for MySQ bug    # Compensate for MySQ bug
73    def __mySqlNeedsLotsOfTLC(self):    def __mySqlNeedsLotsOfTLC(self):
74      if self.__done:      if self.__done:
75        return None        return None
76    
77      self.__done = 1      self.__done = 1
78      return self._cursor.fetchall()      return self._cursor.fetchall()
79    
80    
81    def _loadNextRecord(self):    def _loadNextRecord(self):
82      if self._cursor:      if self._cursor:
83        rs = None        rs = None
84    
85        try:        try:
86          # See __init__ for details          # See __init__ for details
87          rsets = self.fetchBugFix()          rsets = self.fetchBugFix()
88    
89        except self._dataObject._DatabaseError, err:        except self._dataObject._DatabaseError, err:
90          raise GDataObjects.ConnectionError, err          raise GDataObjects.ConnectionError, err
91    
92        if rsets and len(rsets):        if rsets and len(rsets):
93          for rs in(rsets):          for rs in(rsets):
94            if rs:            if rs:
95              i = 0              i = 0
96              dict = {}              dict = {}
97              for f in (rs):              for f in (rs):
98                dict[string.lower(self._fieldNames[i])] = f                dict[string.lower(self._fieldNames[i])] = f
99                i += 1                i += 1
100              self._cachedRecords.append (self._recordSetClass(parent=self, \              self._cachedRecords.append (self._recordSetClass(parent=self, \
101                                                               initialData=dict))                                                               initialData=dict))
102            else:            else:
103              return 0              return 0
104          return 1          return 1
105        else:        else:
106          return 0          return 0
107      else:      else:
108       return 0       return 0
109    
110  class MySQL_DataObject(DBSIG_DataObject):  class MySQL_DataObject(DBSIG_DataObject):
111    def __init__(self):    def __init__(self):
112      DBSIG_DataObject.__init__(self)      DBSIG_DataObject.__init__(self)
113      self._DatabaseError = MySQLdb.DatabaseError      self._DatabaseError = MySQLdb.DatabaseError
114      self._resultSetClass = MySQL_ResultSet      self._resultSetClass = MySQL_ResultSet
115    def connect(self, connectData={}):    def connect(self, connectData={}):
116      GDebug.printMesg(1,"Mysql database driver initializing")      GDebug.printMesg(1,"Mysql database driver initializing")
117    
118      try:      try:
119        self._dataConnection = MySQLdb.connect(user=connectData['_username'],        self._dataConnection = MySQLdb.connect(user=connectData['_username'],
120                     passwd=connectData['_password'],                     passwd=connectData['_password'],
121                     host=connectData['host'],                     host=connectData['host'],
122                     db=connectData['dbname'])                     db=connectData['dbname'])
123      except self._DatabaseError, value:      except self._DatabaseError, value:
124        raise GDataObjects.LoginError, value        raise GDataObjects.LoginError, value
125    
126      self._beginTransaction()      self._beginTransaction()
127      self._postConnect()      self._postConnect()
128    
129    
130    def _postConnect(self):    def _postConnect(self):
131      self.triggerExtensions = TriggerExtensions(self._dataConnection)      self.triggerExtensions = TriggerExtensions(self._dataConnection)
132    
133    
134    def _beginTransaction(self):    def _beginTransaction(self):
135      try:      try:
136        self._dataConnection.begin()        self._dataConnection.begin()
137      except:      except:
138        pass        pass
139    
140    
141    #    #
142    # Schema (metadata) functions    # Schema (metadata) functions
143    #    #
144    
145    # Return a list of the types of Schema objects this driver provides    # Return a list of the types of Schema objects this driver provides
146    def getSchemaTypes(self):    def getSchemaTypes(self):
147      return [('table',_('Tables'),1)]      return [('table',_('Tables'),1)]
148    
149    # Return a list of Schema objects    # Return a list of Schema objects
150    def getSchemaList(self, type=None):    def getSchemaList(self, type=None):
151    
152      # TODO: This excludes any system tables and views. Should it?      # TODO: This excludes any system tables and views. Should it?
153      statement = "SHOW TABLES"      statement = "SHOW TABLES"
154    
155      cursor = self._dataConnection.cursor()      cursor = self._dataConnection.cursor()
156      cursor.execute(statement)      cursor.execute(statement)
157    
158      list = []      list = []
159      for rs in cursor.fetchall():      for rs in cursor.fetchall():
160        list.append(GDataObjects.Schema(attrs={'id':rs[0], 'name':rs[0],        list.append(GDataObjects.Schema(attrs={'id':rs[0], 'name':rs[0],
161                           'type':'table'},                           'type':'table',
162                           getChildSchema=self.__getFieldSchema))                           'primarykey': self.__getPrimaryKey(rs[0])},
163                             getChildSchema=self.__getFieldSchema))
164      cursor.close()  
165      return list      cursor.close()
166        return list
167    
168    # Find a schema object with specified name  
169    def getSchemaByName(self, name, type=None):    # Find a schema object with specified name
170      statement = "DESCRIBE %s" % (name)    def getSchemaByName(self, name, type=None):
171        statement = "DESCRIBE %s" % (name)
172      cursor = self._dataConnection.cursor()  
173      cursor.execute(statement)      cursor = self._dataConnection.cursor()
174        cursor.execute(statement)
175      rs = cursor.fetchone()  
176      if rs:      rs = cursor.fetchone()
177        schema = GDataObjects.Schema(attrs={'id':name, 'name':name,      if rs:
178                             'type':'table'},        schema = GDataObjects.Schema(attrs={'id':name, 'name':name,
179                             getChildSchema=self.__getFieldSchema)                             'type':'table',
180      else:                             'primarykey': self.__getPrimaryKey(name,cursor)},
181        schema = None                             getChildSchema=self.__getFieldSchema)
182        else:
183      cursor.close()        schema = None
184      return schema  
185        cursor.close()
186        return schema
187    # Get fields for a table  
188    def __getFieldSchema(self, parent):  
189      def __getPrimaryKey(self, id, cursor=None):
190      statement = "DESCRIBE %s" % parent.id      statement = "DESCRIBE %s" % id
191        if not cursor:
192      cursor = self._dataConnection.cursor()        cursor = self._dataConnection.cursor()
193      cursor.execute(statement)        close_cursor = 1
194        else:
195      list = []        close_cursor = 0
196      for rs in cursor.fetchall():      cursor.execute(statement)
197    
198        nativetype = string.split(string.replace(rs[1],')',''),'(')      lst = []
199        for rs in cursor.fetchall():
200          if rs[3] == 'PRI':
201        attrs={'id': "%s.%s" % (parent.id, rs[0]), 'name': rs[0],          lst.append(rs[0])
202               'type':'field', 'nativetype': nativetype[0],  
203               'required': rs[2] != 'YES'}      if close_cursor:
204          cursor.close()
205        if nativetype[0] in ('int','integer','bigint','mediumint',  
206                             'smallint','tinyint','float','real',      return tuple(lst)
207                             'double','decimal'):  
208          attrs['datatype']='number'    # Get fields for a table
209        elif nativetype[0] in ('date','time','timestamp','datetime'):    def __getFieldSchema(self, parent):
210          attrs['datatype']='date'  
211        else:      statement = "DESCRIBE %s" % parent.id
212          attrs['datatype']='text'  
213        cursor = self._dataConnection.cursor()
214        try:      cursor.execute(statement)
215          if len(nativetype) == 2:  
216            attrs['length'] = int(string.split(nativetype[1])[0])      list = []
217        except ValueError:      for rs in cursor.fetchall():
218          GDebug.printMesg(1,'WARNING: mysql native type error: %s' % nativetype)  
219          nativetype = string.split(string.replace(rs[1],')',''),'(')
220        list.append(GDataObjects.Schema(attrs=attrs))  
221    
222      cursor.close()        attrs={'id': "%s.%s" % (parent.id, rs[0]), 'name': rs[0],
223      return list               'type':'field', 'nativetype': nativetype[0],
224                 'required': rs[2] != 'YES'}
225    
226          if nativetype[0] in ('int','integer','bigint','mediumint',
227                               'smallint','tinyint','float','real',
228  class MySQL_DataObject_Object(MySQL_DataObject, \                             'double','decimal'):
229        DBSIG_DataObject_Object):          attrs['datatype']='number'
230          elif nativetype[0] in ('date','time','timestamp','datetime'):
231    def __init__(self):          attrs['datatype']='date'
232      MySQL_DataObject.__init__(self)        else:
233            attrs['datatype']='text'
234    def _buildQuery(self, conditions={},forDetail=None,additionalSQL=""):  
235      return DBSIG_DataObject_Object._buildQuery(self, conditions,forDetail,additionalSQL)        try:
236            if len(nativetype) == 2:
237              try:
238  class MySQL_DataObject_SQL(MySQL_DataObject, \              ln, prec = nativetype[1].split(',')
239        DBSIG_DataObject_SQL):            except:
240    def __init__(self):              ln = nativetype[1]
241      # Call DBSIG init first because MySQL_DataObject needs to overwrite              prec = None
242      # some of its values            attrs['length'] = int(ln.split()[0])
243      DBSIG_DataObject_SQL.__init__(self)            if prec != None:
244      MySQL_DataObject.__init__(self)              attrs['precision'] = int(prec)
245          except ValueError:
246    def _buildQuery(self, conditions={}):          GDebug.printMesg(1,'WARNING: mysql native type error: %s' % nativetype)
247      return DBSIG_DataObject_SQL._buildQuery(self, conditions)  
248          if rs[4] not in ('NULL', '0000-00-00 00:00:00','', None):
249            attrs['defaulttype'] = 'constant'
250  #          attrs['defaultval'] = rs[4]
251  #  Extensions to Trigger Namespaces  
252  #          if rs[5] == 'auto_increment':
253  class TriggerExtensions:          attrs['defaulttype'] = 'serial'
254    
255    def __init__(self, connection):  
256      self.__connection = connection        list.append(GDataObjects.Schema(attrs=attrs))
257    
258    # Return the current date, according to database      cursor.close()
259  #  def getDate(self):      return list
260  #    pass  
261    
262    # Return a sequence number from sequence 'name'  
263  #  def getSequence(self, name):  
264  #    pass  class MySQL_DataObject_Object(MySQL_DataObject, \
265          DBSIG_DataObject_Object):
266    # Run the SQL statement 'statement'  
267  #  def sql(self, statement):    def __init__(self):
268  #    pass      MySQL_DataObject.__init__(self)
269    
270      def _buildQuery(self, conditions={},forDetail=None,additionalSQL=""):
271        return DBSIG_DataObject_Object._buildQuery(self, conditions,forDetail,additionalSQL)
272  ######################################  
273  #  
274  #  The following hashes describe  class MySQL_DataObject_SQL(MySQL_DataObject, \
275  #  this driver's characteristings.        DBSIG_DataObject_SQL):
276  #    def __init__(self):
277  ######################################      # Call DBSIG init first because MySQL_DataObject needs to overwrite
278        # some of its values
279  #      DBSIG_DataObject_SQL.__init__(self)
280  #  All datasouce "types" and corresponding DataObject class      MySQL_DataObject.__init__(self)
281  #  
282  supportedDataObjects = {    def _buildQuery(self, conditions={}):
283    'object': MySQL_DataObject_Object,      return DBSIG_DataObject_SQL._buildQuery(self, conditions)
284    'sql':    MySQL_DataObject_SQL  
285  }  
286    #
287    #  Extensions to Trigger Namespaces
288    #  
289    class TriggerExtensions:
290    
291      def __init__(self, connection):
292        self.__connection = connection
293    
294      # Return the current date, according to database
295    #  def getDate(self):
296    #    pass
297    
298      # Return a sequence number from sequence 'name'
299    #  def getSequence(self, name):
300    #    pass
301    
302      # Run the SQL statement 'statement'
303    #  def sql(self, statement):
304    #    pass
305    
306    
307    
308    ######################################
309    #
310    #  The following hashes describe
311    #  this driver's characteristings.
312    #
313    ######################################
314    
315    #
316    #  All datasouce "types" and corresponding DataObject class
317    #
318    supportedDataObjects = {
319      'object': MySQL_DataObject_Object,
320      'sql':    MySQL_DataObject_SQL
321    }
322    
323    

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.5

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26