~ubuntu-branches/ubuntu/hardy/gnue-common/hardy

« back to all changes in this revision

Viewing changes to src/datasources/drivers/Base/Connection.py

  • Committer: Bazaar Package Importer
  • Author(s): Andrew Mitchell
  • Date: 2005-03-09 11:06:31 UTC
  • Revision ID: james.westby@ubuntu.com-20050309110631-8gvvn39q7tjz1kj6
Tags: upstream-0.5.14
ImportĀ upstreamĀ versionĀ 0.5.14

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# GNU Enterprise Common - Base DB Driver - Connection
 
2
#
 
3
# Copyright 2001-2005 Free Software Foundation
 
4
#
 
5
# This file is part of GNU Enterprise
 
6
#
 
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.
 
11
#
 
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.
 
16
#
 
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.
 
21
#
 
22
# $Id: Connection.py 7057 2005-02-23 16:53:58Z johannes $
 
23
 
 
24
import copy
 
25
import string
 
26
 
 
27
__all__ = ['Connection']
 
28
 
 
29
 
 
30
# System Init:
 
31
#   +-- GConnections initializes
 
32
#   +-- GParser initializes:
 
33
#     +-- GDataSource loaded
 
34
#   +-- GDataSources Intialized
 
35
#     +-- GConnection.getDataObject()
 
36
#       +--
 
37
#
 
38
class Connection:
 
39
  def __init__(self, connections, name, parameters):
 
40
    self.manager = connections
 
41
    self.parameters = parameters
 
42
    self.name = name
 
43
 
 
44
    # Text encoding used by the database.
 
45
    # (Not all databases support this concept)
 
46
    try:
 
47
      self._encoding = parameters['encoding']
 
48
    except KeyError:
 
49
      try:
 
50
         self._encoding = gConfig('textEncoding')
 
51
      except:
 
52
        # TODO: Is this a safe default?
 
53
        self._encoding = 'iso8859-1'
 
54
 
 
55
 
 
56
  # Commit changes to the database
 
57
  def commit(self):
 
58
    pass
 
59
 
 
60
  # Rollback changes to the database
 
61
  def rollback(self):
 
62
    pass
 
63
 
 
64
  # Close the connection to the database backend
 
65
  def close (self):
 
66
 
 
67
    # Make sure to release the reference to the connection manager as well as
 
68
    # the introspector's instance (if available). This makes garbage collection
 
69
    # behave nice :)
 
70
    self.manager = None
 
71
    if hasattr (self, 'introspector'):
 
72
      self.introspector = None
 
73
 
 
74
 
 
75
  def connect(self, connectData):
 
76
    pass
 
77
 
 
78
 
 
79
  # ---------------------------------------------------------------------------
 
80
  # Create a new instance of the associated schema creator
 
81
  # ---------------------------------------------------------------------------
 
82
 
 
83
  def getSchemaCreator (self):
 
84
    """
 
85
    This function creates a new instance of the schema creator associated with
 
86
    this driver or None if no creator is available.
 
87
    """
 
88
 
 
89
    if hasattr (self, 'defaultCreator') and self.defaultCreator:
 
90
      return self.defaultCreator (self)
 
91
    else:
 
92
      return None
 
93
 
 
94
 
 
95
  # ---------------------------------------------------------------------------
 
96
  # update the schema definition 
 
97
  # ---------------------------------------------------------------------------
 
98
 
 
99
  def updateSchema (self, definition, codeOnly = False):
 
100
    """
 
101
    This function modifies the database schema according to the given
 
102
    definition, which is a dictionary of table defininitions (@see:
 
103
    Schema.Creation.Creation), where the tablenames are the keys.
 
104
 
 
105
    @param definition: sequence of table definitions
 
106
    @param codeOnly: if TRUE, only the code will be generated to modify the
 
107
        schema, no actions take place.
 
108
    @return: a tuple of three sequences (prologue, body, epilogue) holding the
 
109
        code to perform all schema modifications needed. These sequences should
 
110
        be executed in this order to successfully create the schema.
 
111
    """
 
112
 
 
113
    result = ([], [], [])
 
114
 
 
115
    schemaCreator = self.getSchemaCreator ()
 
116
 
 
117
    if schemaCreator is None:
 
118
      return result
 
119
 
 
120
    try:
 
121
      workingSet    = copy.copy (definition)
 
122
      constraintSet = {}
 
123
 
 
124
      # before any actions are performed, validate the given definitions
 
125
      for table in definition:
 
126
        schemaCreator.validate (table)
 
127
 
 
128
      # in a first run we remove all constraint definitions from the tables, so
 
129
      # we can add or alter all tables without having troubles with order of
 
130
      # occurence.
 
131
      for table in workingSet:
 
132
        # Do we have already a table with that name?
 
133
        res = self.introspector.find (name = table ['name'])
 
134
 
 
135
        if res is not None:
 
136
          method = schemaCreator.modifyTable
 
137
          # Please note: we keep existingFields sequence in all lowercase
 
138
          existingFields = [f.name.lower () for f in res [0].fields ()]
 
139
 
 
140
          # keep only new fields
 
141
          keep = []
 
142
          for field in table ['fields']:
 
143
            if not field ['name'].lower () in existingFields:
 
144
              keep.append (field)
 
145
 
 
146
          table ['fields'] = keep
 
147
 
 
148
          # on updates of a table we cannot use a primary key
 
149
          if table.has_key ('primarykey'):
 
150
            del table ['primarykey']
 
151
  
 
152
          # keep modified or new indices only
 
153
          if table.has_key ('indices'):
 
154
            keep = []
 
155
 
 
156
            # if driver supports index-introspection we'll use it
 
157
            if hasattr (res [0], 'indices'):
 
158
              for index in table ['indices']:
 
159
                oldIndex = None
 
160
                for (name, value) in res [0].indices.items ():
 
161
                  if name.lower () == index ['name'].lower ():
 
162
                    oldIndex = value
 
163
 
 
164
                if oldIndex is None:
 
165
                  keep.append (index)
 
166
                else:
 
167
                  old = [f.lower () for f in oldIndex ['fields']]
 
168
                  new = [f.lower () for f in index ['fields']]
 
169
 
 
170
                  if oldIndex ['unique'] != index ['unique'] or old != new:
 
171
 
 
172
                    # make sure the backend has a possibility to remove the old
 
173
                    # index before changing it
 
174
                    if not table.has_key ('old_indices'):
 
175
                      table ['old_indices'] = []
 
176
                    table ['old_indices'].append (index ['name'])
 
177
 
 
178
                    keep.append (index)
 
179
            else:
 
180
              # if no index-introspection available we only keep an index, if it
 
181
              # has new fields
 
182
              for index in table ['indices']:
 
183
                for field in index ['fields']:
 
184
                  if not field.lower () in existingFields:
 
185
                    # make sure the backend has a possibility to remove the old
 
186
                    # index before changing it
 
187
                    if not table.has_key ('old_indices'):
 
188
                      table ['old_indices'] = []
 
189
                    table ['old_indices'].append (index ['name'])
 
190
 
 
191
                    keep.append (index)
 
192
                    break
 
193
 
 
194
            table ['indices'] = keep
 
195
 
 
196
          # we create a constraint on a table update only if it contains new
 
197
          # fields
 
198
          if table.has_key ('constraints'):
 
199
            keep = []
 
200
 
 
201
            for constraint in table ['constraints']:
 
202
              for field in constraint ['fields']:
 
203
                if not field.lower () in existingFields:
 
204
                  keep.append (constraint)
 
205
                  break
 
206
 
 
207
            table ['constraints'] = keep
 
208
 
 
209
        else:
 
210
          method = schemaCreator.createTable
 
211
 
 
212
        if table.has_key ('constraints'):
 
213
          constraintSet [table ['name']] = {'name':        table ['name'],
 
214
                                          'constraints': table ['constraints']}
 
215
          del table ['constraints']
 
216
 
 
217
        # before we execute the planned action, have a look if there's still
 
218
        # work to be done
 
219
        perform = table.has_key ('fields') and len (table ['fields'])
 
220
        perform = perform or table.has_key ('primarykey')
 
221
        perform = perform or (table.has_key ('indices') and \
 
222
                              len (table ['indices']))
 
223
 
 
224
        if perform:
 
225
          schemaCreator.mergeTuple (result, method (table, codeOnly))
 
226
 
 
227
      # on the second run we process all constraints
 
228
      for table in constraintSet.values ():
 
229
        schemaCreator.mergeTuple (result,
 
230
                                schemaCreator.createTable (table, codeOnly))
 
231
      return result
 
232
 
 
233
    finally:
 
234
      schemaCreator.close ()