1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 __docformat__ = "epytext en"
100
101 """
102 Defines abstract class datasource, baseclass for adapter.*.datasource.
103
104 The datasource module defines the datasource class and a number of
105 conveniance classes for managing query results.
106 """
107
108
109 from types import *
110 import string
111
112
113 from orm2.debug import sqllog, debug
114 from orm2.exceptions import *
115 from orm2 import sql, keys
116 from orm2.util import stupid_dict
117
119 """
120 Return a ORM datasource object constructed from a connection
121 string or a number of keyword arguments.
122
123 The connection strings follow the conventions for PostgreSQL DSNs:
124 they consist of keyword=value pairs seperated with whitespace.
125 Keywords recognized are::
126
127 adapter - name of the ORM adapter used. Use the name from the
128 adapters/ directory.
129 db - name of the database to connect to
130 user - Database username
131 password - Password used for authentication
132 host - hostname or IP address of the machine the database
133 runs on (note that there might be a difference if you
134 use 127.0.0.1 or localhost. The first creating a tcp/ip
135 connection, the latter a unix/fifo connection. This is
136 true for at leas pgsql and mysql
137 debug - if set SQL queries will be printed to stdout (actually
138 the debug.debug function is called so you can overload
139 it)
140
141 Each of the database backends may define its own keywords. For
142 instance PostgreSQL will understand each of the original keywords
143 as aliases. Check the documentation!
144
145 Values may not contain spaces.
146
147 If you prefer to use the keyword argument syntax, the paramters must
148 be the key and their arguments the values::
149
150 datasource('db=test user=diedrich password=kfjdh')
151
152 equals::
153
154 datasource(db='test', user='diedrich', password='kfjdh')
155 """
156
157 try:
158 parts = string.splitfields(connection_string)
159 params = {}
160 for part in parts:
161 name, value = string.split(part, "=")
162 if name != "" and value != "":
163 params[name] = value
164 else:
165 raise ValueError()
166 except ValueError, msg:
167 raise IllegalConnectionString("%s (%s)" % (connection_string,
168 msg))
169
170 params.update(kwargs)
171
172 try:
173 adapter = params["adapter"]
174 except KeyError:
175 raise IllegalConnectionString(
176 "%s (The adapter= keyword must always be present!)" %connection_string)
177
178 del params["adapter"]
179
180 if adapter == "gadfly":
181 from orm2.adapters.gadfly.datasource import datasource
182 elif adapter == "pgsql":
183 from orm2.adapters.pgsql.datasource import datasource
184 elif adapter == "mysql":
185 from orm2.adapters.mysql.datasource import datasource
186 elif adapter == "firebird":
187 from orm2.adapters.firebird.datasource import datasource
188 else:
189 raise IllegalConnectionString("Unknown adapter: %s" % adapter)
190
191 if params.has_key("debug"):
192 debug = True
193 del params["debug"]
194 else:
195 debug = False
196
197 ds = datasource.from_params(params)
198 ds._debug = debug
199
200 return ds
201
203 """
204 The DataSource encapsulates the functionality we need to talk to the
205 database. Most notably are the insert, select and delete methods.
206
207 This class must be subclassed by the adapter.*.datasource.datasource
208 classes.
209
210 It inherits from sql.datasource to provide default implmentations of
211 the methods the sql module depends upon.
212 """
213
214 escaped_chars = [ ("\\", "\\\\"),
215 ("'", "\\'"),
216 ('"', '\\"'),
217 ("%", "%%",), ]
218
219 _format_funcs = {}
220
222 self._conn = None
223 self._updates = stupid_dict()
224 self._update_cursor = None
225 self._debug = 0
226
228 """
229 Return the dbconn for this ds
230 """
231 return self._conn
232
234 """
235 This method is ment for results that return exactly one row or item
236
237 It will:
238
239 - return None if there is an empty result returned
240 - if there are more than one result row, return the result as is
241 (a tuple of tuples)
242 - if there is only one row, but several columns, return the row as
243 a tuple
244 - if the only row has only one column, return the value of the
245 column
246
247 @param query: A string containing an SQL query.
248 """
249 cursor = self.execute(query)
250 result = cursor.fetchone()
251
252 try:
253 if len(result) == 1: return result[0]
254 except TypeError:
255 return result
256
257 - def execute(self, command, modify=False):
258 """
259 Execute COMMAND on the database. If modify is True, the command
260 is assumed to modify the database. All modifying commands
261 will be executed on the same cursor.
262
263 @param command: A string containing an SQL command of any kind or an
264 sql.statement instance.
265 """
266 if type(command) == UnicodeType:
267 raise TypeError("Database queries must be strings, not unicode")
268
269 if modify:
270 cursor = self.update_cursor()
271 else:
272 cursor = self._dbconn().cursor()
273
274 if isinstance(command, sql.statement):
275 runner = sql.sql(self)
276 command = runner(command)
277 params = runner.params
278 else:
279 params = ()
280
281 print >> sqllog, "command:", command, "params", repr(params)
282
283 cursor.execute(command, tuple(params))
284
285
286
287 return cursor
288
290 """
291 Run commit on this ds's connection. You need to do this for any
292 change you really want to happen!
293 """
294 cursor = self.flush_updates()
295 self._dbconn().commit()
296
298 """
299 Undo the changes you made to the database since the last commit()
300 """
301 self._updates.clear()
302 self._dbconn().rollback()
303
305 """
306 Return a newly created dbi cursor.
307 """
308 return self._dbconn().cursor()
309
311 """
312 Close the connection to the database.
313 """
314 self._dbconn().close()
315
317 """
318 Return the cursor that this ds uses for any query that modifies
319 the database (to keep the transaction together).
320 """
321 if getattr(self, "_update_cursor", None) is None:
322 self._update_cursor = self.cursor()
323
324 return self._update_cursor
325
326
327 - def select(self, dbclass, *clauses):
328 """
329 SELECT dbobjs from the database, according to clauses.
330
331 @param dbclass: The dbclass of the objects to be selected.
332
333 @param clauses: A list of orm2.sql clauses instances (or
334 equivalent Python object i.e. strings) that
335 are added to the sql.select query. See
336 orm2.sql.select for details
337
338
339 """
340 query = sql.select(dbclass.__select_columns__(),
341 dbclass.__relation__, *clauses)
342
343 return self.run_select(dbclass, query)
344
345
347 """
348 Run a select statement on this datasource that is ment to return
349 rows suitable to construct objects of dbclass from them.
350
351 @param dbclass: The dbclass of the objects to be selected
352 @param select: sql.select instance representing the query
353 """
354 return dbclass.__result__(self, dbclass, select)
355
357 """
358 This method is ment for queries of which you know that they
359 will return exactly one dbobj. It will set a limit=1 clause.
360 If the result is empty, it will return None, otherwise the
361 selected dbobj.
362 """
363 clauses += (sql.limit(1),)
364
365 result = self.select(dbclass, *clauses)
366
367 try:
368 return result.next()
369 except StopIteration:
370 return None
371
372 - def count(self, dbclass, *clauses):
373 """
374 All clauses except the WHERE clause will be ignored
375 (including OFFSET and LIMIT!)
376
377 @param dbclass: See select() above.
378 @param clauses: See select() above.
379
380 @return: An integer value indicating the number of objects
381 of dbclass select() would return if run with these clauses.
382 """
383
384 where = None
385 for clause in clauses:
386 if isinstance(clause, sql.where):
387 where = clause
388
389 if where is not None:
390 clauses = [where]
391 else:
392 clauses = []
393
394 query = sql.select("COUNT(*)", dbclass.__relation__, *clauses)
395 return self.query_one(query)
396
398
399 pass
400
432
434 """
435 Select a single object of dbclass from its relation, identified
436 by its primary key.
437
438 @param dbclass: Dbclass to be selected
439 @param key: Python value representing the primary key or a tuple of
440 such Python values, if the primary key has multiple columns
441 @raise IllegalPrimaryKey: hallo
442 @return: A single dbobj.
443 """
444 where = self.primary_key_where(dbclass, key)
445 result = self.select(dbclass, where)
446
447 try:
448 return result.next()
449 except StopIteration:
450 return None
451
453 """
454 This method works like L{select_by_primary_key} above, except that it
455 doesn't select anything but returns a dummy object (an empty dbobj)
456 that will allow setting attributes, yielding proper UPDATE statements.
457 Note that supplying a primary key that does not exist will go
458 unnoticed: The UPDATE statements won't create an error, they just
459 won't affect any rows.
460
461 This method is primarily ment for transaction based (i.e. www)
462 applications.
463 """
464 if type(key) != TupleType: key = ( key, )
465 primary_key = keys.primary_key(dbclass)
466
467 if len(key) != len(primary_key.key_attributes):
468 msg = "The primary key for %s must have %i elements." % \
469 ( repr(dbclass), len(primary_key.key_attributes), )
470 raise IllegalPrimaryKey(msg)
471
472 info = stupid_dict()
473 for property, value in zip(primary_key.attributes(), key):
474 info[property.column] = value
475
476 return dbclass.__from_result__(self, info)
477
478 - def insert(self, dbobj, dont_select=False):
508
531
533 raise NotImplemented()
534
535 - def update(self, relation, column, sql_literal, where, ):
536 """
537 Updates are stored in a list and executed on calls to commit() or to
538 flush_updates() to join updates to the same row into a single SQL
539 command.
540
541 @param relation: The relation to be updated
542 @param column: sql.column Name of the column to be updated
543 @param sql_literal: sql literal of the value to be stored.
544 @param where: where clause that would select (or update in this case)
545 the desired row from relation
546 """
547 key = ( relation, where, )
548 data = self._updates.get(key, stupid_dict())
549 data[column] = sql_literal
550 self._updates[key] = data
551
563
566
571
572
573
574
575
576
577