1
# GNU Enterprise Common - MySQL DB driver - Schema Introspection
3
# Copyright 2001-2005 Free Software Foundation
5
# This file is part of GNU Enterprise
7
# GNU Enterprise is free software; you can redistribute it
8
# and/or modify it under the terms of the GNU General Public
9
# License as published by the Free Software Foundation; either
10
# version 2, or (at your option) any later version.
12
# GNU Enterprise is distributed in the hope that it will be
13
# useful, but WITHOUT ANY WARRANTY; without even the implied
14
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15
# PURPOSE. See the GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public
18
# License along with program; see the file COPYING. If not,
19
# write to the Free Software Foundation, Inc., 59 Temple Place
20
# - Suite 330, Boston, MA 02111-1307, USA.
22
# $Id: Introspection.py 6851 2005-01-03 20:59:28Z jcater $
24
__all__ = ['Introspection']
28
from gnue.common.datasources import GIntrospection
30
# =============================================================================
31
# This class implements schema introspection for MySQL backends
32
# =============================================================================
34
class Introspection (GIntrospection.Introspection):
36
# list of the types of Schema objects this driver provides
37
types = [('table', _('Tables'), 1)]
39
_TYPES = {'number': ['int','integer','bigint','mediumint',
40
'smallint','tinyint','float','real', 'double','decimal'],
41
'date' : ['date','time','timestamp','datetime']}
43
# ---------------------------------------------------------------------------
44
# Find a schema element by name and/or type
45
# ---------------------------------------------------------------------------
47
def find (self, name = None, type = None):
49
This function searches the schema for an element by name and/or type. If no
50
name and no type is given, all elements will be retrieved.
52
@param name: look for an element with this name
53
@param type: look for an element with this type
55
@return: A sequence of schema instances, one per element found, or None if
56
no element could be found.
65
cmd = u"SHOW COLUMNS FROM %s" % name
68
cursor = self._connection.makecursor (cmd)
78
for rs in cursor.fetchall ():
79
attrs = {'id' : name or rs [0],
80
'name' : name or rs [0],
83
'indices' : self.__getIndices (name or rs [0])}
85
if attrs ['indices'] is not None:
86
for index in attrs ['indices'].values ():
88
attrs ['primarykey'] = index ['fields']
92
GIntrospection.Schema (attrs, getChildSchema = self._getChildSchema))
101
return len (result) and result or None
104
# ---------------------------------------------------------------------------
105
# Get all fields of a table
106
# ---------------------------------------------------------------------------
108
def _getChildSchema (self, parent):
110
This function returns a list of all child elements for a given table.
112
@param parent: schema object instance whose child elements should be
114
@return: sequence of schema instances
119
cmd = u"SHOW COLUMNS FROM %s" % parent.id
121
cursor = self._connection.makecursor (cmd)
124
for rs in cursor.fetchall ():
125
nativetype = string.split (string.replace (rs [1], ')', ''), '(')
127
attrs = {'id' : "%s.%s" % (parent.id, rs [0]),
130
'nativetype': nativetype [0],
131
'required' : rs [2] != 'YES',
134
for (group, natives) in self._TYPES.items ():
135
if nativetype [0] in natives:
136
attrs ['datatype'] = group
139
if len (nativetype) == 2:
141
for item in nativetype [1].split (','):
142
parts.extend (item.split ())
144
if parts [0].strip ().isdigit ():
145
attrs ['length'] = int (parts [0].strip ())
147
if len (parts) > 1 and parts [1].strip ().isdigit ():
148
attrs ['precision'] = int (parts [1].strip ())
150
if rs [4] not in ('NULL', '0000-00-00 00:00:00', '', None):
151
attrs ['defaulttype'] = 'constant'
152
attrs ['defaultval'] = rs [4]
154
if rs [5] == 'auto_increment':
155
attrs ['defaulttype'] = 'serial'
157
result.append (GIntrospection.Schema (attrs))
165
# ---------------------------------------------------------------------------
166
# Get a dictionary of all indices available for a given table
167
# ---------------------------------------------------------------------------
169
def __getIndices (self, table):
171
This function creates a dictionary with all indices of a given relation
172
where the keys are the indexnames and the values are dictionaries
173
describing the indices. Such a dictionary has the keys 'unique', 'primary'
174
and 'fields', where 'unique' specifies whether the index is unique or not
175
and 'primary' specifies wether the index is the primary key or not.
176
'fields' holds a sequence with all field names building the index.
178
@param table: name of the table to fetch indices for
179
@return: dictionary with indices or None if no indices were found
184
cmd = u"SHOW INDEX FROM %s" % table
186
cursor = self._connection.makecursor (cmd)
189
for rs in cursor.fetchall ():
191
if not result.has_key (ixName):
192
result [ixName] = {'unique': not rs [1],
193
'primary': ixName == 'PRIMARY',
195
result [ixName] ['fields'].append ((rs [3], rs [4]))
198
# Sort the field lists according to their sequence number and remove the
199
# sequences number from the list
200
for index in result.values ():
201
fields = index ['fields']
203
index ['fields'] = [field [1] for field in fields]
208
return len (result.keys ()) and result or None