1 """MySQLdb Cursors
2
3 This module implements Cursors of various types for MySQLdb. By
4 default, MySQLdb uses the Cursor class.
5
6 """
7
8 import re
9 insert_values = re.compile(r"\svalues\s*(\(((?<!\\)'.*?\).*(?<!\\)?'|.)+?\))", re.IGNORECASE)
10 from _mysql_exceptions import Warning, Error, InterfaceError, DataError, \
11 DatabaseError, OperationalError, IntegrityError, InternalError, \
12 NotSupportedError, ProgrammingError
13
14
16
17 """A base for Cursor classes. Useful attributes:
18
19 description
20 A tuple of DB API 7-tuples describing the columns in
21 the last executed query; see PEP-249 for details.
22
23 description_flags
24 Tuple of column flags for last query, one entry per column
25 in the result set. Values correspond to those in
26 MySQLdb.constants.FLAG. See MySQL documentation (C API)
27 for more information. Non-standard extension.
28
29 arraysize
30 default number of rows fetchmany() will fetch
31
32 """
33
34 from _mysql_exceptions import MySQLError, Warning, Error, InterfaceError, \
35 DatabaseError, DataError, OperationalError, IntegrityError, \
36 InternalError, ProgrammingError, NotSupportedError
37
38 _defer_warnings = False
39
41 from weakref import proxy
42
43 self.connection = proxy(connection)
44 self.description = None
45 self.description_flags = None
46 self.rowcount = -1
47 self.arraysize = 1
48 self._executed = None
49 self.lastrowid = None
50 self.messages = []
51 self.errorhandler = connection.errorhandler
52 self._result = None
53 self._warnings = 0
54 self._info = None
55 self.rownumber = None
56
58 self.close()
59 self.errorhandler = None
60 self._result = None
61
63 """Close the cursor. No further queries will be possible."""
64 if not self.connection: return
65 while self.nextset(): pass
66 self.connection = None
67
69 if not self._executed:
70 self.errorhandler(self, ProgrammingError, "execute() first")
71
73 from warnings import warn
74 if self._warnings:
75 warnings = self._get_db().show_warnings()
76 if warnings:
77
78
79 for w in warnings:
80 self.messages.append((self.Warning, w))
81 for w in warnings:
82 warn(w[-1], self.Warning, 3)
83 elif self._info:
84 self.messages.append((self.Warning, self._info))
85 warn(self._info, self.Warning, 3)
86
88 """Advance to the next result set.
89
90 Returns None if there are no more result sets.
91 """
92 if self._executed:
93 self.fetchall()
94 del self.messages[:]
95
96 db = self._get_db()
97 nr = db.next_result()
98 if nr == -1:
99 return None
100 self._do_get_result()
101 self._post_get_result()
102 self._warning_check()
103 return 1
104
105 - def _post_get_result(self): pass
106
108 db = self._get_db()
109 self._result = self._get_result()
110 self.rowcount = db.affected_rows()
111 self.rownumber = 0
112 self.description = self._result and self._result.describe() or None
113 self.description_flags = self._result and self._result.field_flags() or None
114 self.lastrowid = db.insert_id()
115 self._warnings = db.warning_count()
116 self._info = db.info()
117
120
122 """Does nothing, required by DB API."""
123
125 if not self.connection:
126 self.errorhandler(self, ProgrammingError, "cursor closed")
127 return self.connection
128
129 - def execute(self, query, args=None):
130
131 """Execute a query.
132
133 query -- string, query to execute on server
134 args -- optional sequence or mapping, parameters to use with query.
135
136 Note: If args is a sequence, then %s must be used as the
137 parameter placeholder in the query. If a mapping is used,
138 %(key)s must be used as the placeholder.
139
140 Returns long integer rows affected, if any
141
142 """
143 from types import ListType, TupleType
144 from sys import exc_info
145 del self.messages[:]
146 db = self._get_db()
147 charset = db.character_set_name()
148 if isinstance(query, unicode):
149 query = query.encode(charset)
150 if args is not None:
151 query = query % db.literal(args)
152 try:
153 r = self._query(query)
154 except TypeError, m:
155 if m.args[0] in ("not enough arguments for format string",
156 "not all arguments converted"):
157 self.messages.append((ProgrammingError, m.args[0]))
158 self.errorhandler(self, ProgrammingError, m.args[0])
159 else:
160 self.messages.append((TypeError, m))
161 self.errorhandler(self, TypeError, m)
162 except:
163 exc, value, tb = exc_info()
164 del tb
165 self.messages.append((exc, value))
166 self.errorhandler(self, exc, value)
167 self._executed = query
168 if not self._defer_warnings: self._warning_check()
169 return r
170
172
173 """Execute a multi-row query.
174
175 query -- string, query to execute on server
176
177 args
178
179 Sequence of sequences or mappings, parameters to use with
180 query.
181
182 Returns long integer rows affected, if any.
183
184 This method improves performance on multiple-row INSERT and
185 REPLACE. Otherwise it is equivalent to looping over args with
186 execute().
187
188 """
189 del self.messages[:]
190 db = self._get_db()
191 if not args: return
192 charset = db.character_set_name()
193 if isinstance(query, unicode): query = query.encode(charset)
194 m = insert_values.search(query)
195 if not m:
196 r = 0
197 for a in args:
198 r = r + self.execute(query, a)
199 return r
200 p = m.start(1)
201 e = m.end(1)
202 qv = m.group(1)
203 try:
204 q = [ qv % db.literal(a) for a in args ]
205 except TypeError, msg:
206 if msg.args[0] in ("not enough arguments for format string",
207 "not all arguments converted"):
208 self.messages.append((ProgrammingError, msg.args[0]))
209 self.errorhandler(self, ProgrammingError, msg.args[0])
210 else:
211 self.messages.append((TypeError, msg))
212 self.errorhandler(self, TypeError, msg)
213 except:
214 from sys import exc_info
215 exc, value, tb = exc_info()
216 del tb
217 self.errorhandler(self, exc, value)
218 r = self._query('\n'.join([query[:p], ',\n'.join(q), query[e:]]))
219 if not self._defer_warnings: self._warning_check()
220 return r
221
223
224 """Execute stored procedure procname with args
225
226 procname -- string, name of procedure to execute on server
227
228 args -- Sequence of parameters to use with procedure
229
230 Returns the original args.
231
232 Compatibility warning: PEP-249 specifies that any modified
233 parameters must be returned. This is currently impossible
234 as they are only available by storing them in a server
235 variable and then retrieved by a query. Since stored
236 procedures return zero or more result sets, there is no
237 reliable way to get at OUT or INOUT parameters via callproc.
238 The server variables are named @_procname_n, where procname
239 is the parameter above and n is the position of the parameter
240 (from zero). Once all result sets generated by the procedure
241 have been fetched, you can issue a SELECT @_procname_0, ...
242 query using .execute() to get any OUT or INOUT values.
243
244 Compatibility warning: The act of calling a stored procedure
245 itself creates an empty result set. This appears after any
246 result sets generated by the procedure. This is non-standard
247 behavior with respect to the DB-API. Be sure to use nextset()
248 to advance through all result sets; otherwise you may get
249 disconnected.
250 """
251
252 from types import UnicodeType
253 db = self._get_db()
254 charset = db.character_set_name()
255 for index, arg in enumerate(args):
256 q = "SET @_%s_%d=%s" % (procname, index,
257 db.literal(arg))
258 if isinstance(q, unicode):
259 q = q.encode(charset)
260 self._query(q)
261 self.nextset()
262
263 q = "CALL %s(%s)" % (procname,
264 ','.join(['@_%s_%d' % (procname, i)
265 for i in range(len(args))]))
266 if type(q) is UnicodeType:
267 q = q.encode(charset)
268 self._query(q)
269 self._executed = q
270 if not self._defer_warnings: self._warning_check()
271 return args
272
274 db = self._get_db()
275 self._last_executed = q
276 db.query(q)
277 self._do_get_result()
278 return self.rowcount
279
281
283 if not self._result:
284 return ()
285 return self._result.fetch_row(size, self._fetch_type)
286
289
290 Warning = Warning
291 Error = Error
292 InterfaceError = InterfaceError
293 DatabaseError = DatabaseError
294 DataError = DataError
295 OperationalError = OperationalError
296 IntegrityError = IntegrityError
297 InternalError = InternalError
298 ProgrammingError = ProgrammingError
299 NotSupportedError = NotSupportedError
300
301
303
304 """This is a MixIn class which causes the entire result set to be
305 stored on the client side, i.e. it uses mysql_store_result(). If the
306 result set can be very large, consider adding a LIMIT clause to your
307 query, or using CursorUseResultMixIn instead."""
308
310
315
317 self._rows = self._fetch_row(0)
318 self._result = None
319
321 """Fetches a single row from the cursor. None indicates that
322 no more rows are available."""
323 self._check_executed()
324 if self.rownumber >= len(self._rows): return None
325 result = self._rows[self.rownumber]
326 self.rownumber = self.rownumber+1
327 return result
328
330 """Fetch up to size rows from the cursor. Result set may be smaller
331 than size. If size is not defined, cursor.arraysize is used."""
332 self._check_executed()
333 end = self.rownumber + (size or self.arraysize)
334 result = self._rows[self.rownumber:end]
335 self.rownumber = min(end, len(self._rows))
336 return result
337
339 """Fetchs all available rows from the cursor."""
340 self._check_executed()
341 if self.rownumber:
342 result = self._rows[self.rownumber:]
343 else:
344 result = self._rows
345 self.rownumber = len(self._rows)
346 return result
347
366
368 self._check_executed()
369 result = self.rownumber and self._rows[self.rownumber:] or self._rows
370 return iter(result)
371
372
374
375 """This is a MixIn class which causes the result set to be stored
376 in the server and sent row-by-row to client side, i.e. it uses
377 mysql_use_result(). You MUST retrieve the entire result set and
378 close() the cursor before additional queries can be peformed on
379 the connection."""
380
381 _defer_warnings = True
382
384
386 """Fetches a single row from the cursor."""
387 self._check_executed()
388 r = self._fetch_row(1)
389 if not r:
390 self._warning_check()
391 return None
392 self.rownumber = self.rownumber + 1
393 return r[0]
394
396 """Fetch up to size rows from the cursor. Result set may be smaller
397 than size. If size is not defined, cursor.arraysize is used."""
398 self._check_executed()
399 r = self._fetch_row(size or self.arraysize)
400 self.rownumber = self.rownumber + len(r)
401 if not r:
402 self._warning_check()
403 return r
404
412
415
417 row = self.fetchone()
418 if row is None:
419 raise StopIteration
420 return row
421
422
424
425 """This is a MixIn class that causes all rows to be returned as tuples,
426 which is the standard form required by DB API."""
427
428 _fetch_type = 0
429
430
432
433 """This is a MixIn class that causes all rows to be returned as
434 dictionaries. This is a non-standard feature."""
435
436 _fetch_type = 1
437
439 """Fetch a single row as a dictionary. Deprecated:
440 Use fetchone() instead. Will be removed in 1.3."""
441 from warnings import warn
442 warn("fetchoneDict() is non-standard and will be removed in 1.3",
443 DeprecationWarning, 2)
444 return self.fetchone()
445
447 """Fetch several rows as a list of dictionaries. Deprecated:
448 Use fetchmany() instead. Will be removed in 1.3."""
449 from warnings import warn
450 warn("fetchmanyDict() is non-standard and will be removed in 1.3",
451 DeprecationWarning, 2)
452 return self.fetchmany(size)
453
455 """Fetch all available rows as a list of dictionaries. Deprecated:
456 Use fetchall() instead. Will be removed in 1.3."""
457 from warnings import warn
458 warn("fetchallDict() is non-standard and will be removed in 1.3",
459 DeprecationWarning, 2)
460 return self.fetchall()
461
462
464
465 """This is a MixIn class that returns rows as dictionaries with
466 the same key convention as the old Mysqldb (MySQLmodule). Don't
467 use this."""
468
469 _fetch_type = 2
470
471
472 -class Cursor(CursorStoreResultMixIn, CursorTupleRowsMixIn,
473 BaseCursor):
474
475 """This is the standard Cursor class that returns rows as tuples
476 and stores the result set in the client."""
477
478
479 -class DictCursor(CursorStoreResultMixIn, CursorDictRowsMixIn,
480 BaseCursor):
481
482 """This is a Cursor class that returns rows as dictionaries and
483 stores the result set in the client."""
484
485
486 -class SSCursor(CursorUseResultMixIn, CursorTupleRowsMixIn,
487 BaseCursor):
488
489 """This is a Cursor class that returns rows as tuples and stores
490 the result set in the server."""
491
492
493 -class SSDictCursor(CursorUseResultMixIn, CursorDictRowsMixIn,
494 BaseCursor):
495
496 """This is a Cursor class that returns rows as dictionaries and
497 stores the result set in the server."""
498