Mercurial > p > mysql-python > mysqldb-2
annotate MySQLdb/cursors.py @ 57:9ea2b0e9302e MySQLdb
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
author | adustman |
---|---|
date | Sat, 28 Feb 2009 04:06:44 +0000 |
parents | 6e31278d3433 |
children | 2d6a35051f64 |
rev | line source |
---|---|
14 | 1 """ |
2 MySQLdb Cursors | |
3 --------------- | |
0 | 4 |
5 This module implements Cursors of various types for MySQLdb. By | |
6 default, MySQLdb uses the Cursor class. | |
7 | |
8 """ | |
9 | |
14 | 10 __revision__ = "$Revision$"[11:-2] |
11 __author__ = "$Author$"[9:-2] | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
12 |
0 | 13 import re |
54
6e31278d3433
There's no good reason to delay imports when the module is (1) useless without
kylev
parents:
31
diff
changeset
|
14 import sys |
6e31278d3433
There's no good reason to delay imports when the module is (1) useless without
kylev
parents:
31
diff
changeset
|
15 import weakref |
0 | 16 |
31 | 17 INSERT_VALUES = re.compile(r"\svalues\s*" |
18 r"(\(((?<!\\)'[^\)]*?\)[^\)]*(?<!\\)?'" | |
19 r"|[^\(\)]|" | |
20 r"(?:\([^\)]*\))" | |
21 r")+\))") | |
0 | 22 |
23 class BaseCursor(object): | |
24 | |
25 """A base for Cursor classes. Useful attributes: | |
26 | |
27 description | |
28 A tuple of DB API 7-tuples describing the columns in | |
29 the last executed query; see PEP-249 for details. | |
30 | |
31 description_flags | |
32 Tuple of column flags for last query, one entry per column | |
33 in the result set. Values correspond to those in | |
34 MySQLdb.constants.FLAG. See MySQL documentation (C API) | |
35 for more information. Non-standard extension. | |
36 | |
37 arraysize | |
38 default number of rows fetchmany() will fetch | |
39 | |
40 """ | |
41 | |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
42 from MySQLdb.exceptions import MySQLError, Warning, Error, InterfaceError, \ |
0 | 43 DatabaseError, DataError, OperationalError, IntegrityError, \ |
44 InternalError, ProgrammingError, NotSupportedError | |
54
6e31278d3433
There's no good reason to delay imports when the module is (1) useless without
kylev
parents:
31
diff
changeset
|
45 |
4 | 46 _defer_warnings = False |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
47 _fetch_type = None |
54
6e31278d3433
There's no good reason to delay imports when the module is (1) useless without
kylev
parents:
31
diff
changeset
|
48 |
0 | 49 def __init__(self, connection): |
54
6e31278d3433
There's no good reason to delay imports when the module is (1) useless without
kylev
parents:
31
diff
changeset
|
50 self.connection = weakref.proxy(connection) |
0 | 51 self.description = None |
52 self.description_flags = None | |
53 self.rowcount = -1 | |
54 self.arraysize = 1 | |
55 self._executed = None | |
56 self.lastrowid = None | |
57 self.messages = [] | |
58 self.errorhandler = connection.errorhandler | |
59 self._result = None | |
60 self._warnings = 0 | |
61 self._info = None | |
62 self.rownumber = None | |
54
6e31278d3433
There's no good reason to delay imports when the module is (1) useless without
kylev
parents:
31
diff
changeset
|
63 |
0 | 64 def __del__(self): |
65 self.close() | |
66 self.errorhandler = None | |
67 self._result = None | |
54
6e31278d3433
There's no good reason to delay imports when the module is (1) useless without
kylev
parents:
31
diff
changeset
|
68 |
0 | 69 def close(self): |
70 """Close the cursor. No further queries will be possible.""" | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
71 if not self.connection: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
72 return |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
73 try: |
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
74 while self.nextset(): |
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
75 pass |
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
76 except: |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
77 pass |
0 | 78 self.connection = None |
79 | |
80 def _check_executed(self): | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
81 """Ensure that .execute() has been called.""" |
0 | 82 if not self._executed: |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
83 self.errorhandler(self, self.ProgrammingError, "execute() first") |
0 | 84 |
85 def _warning_check(self): | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
86 """Check for warnings, and report via the warnings module.""" |
0 | 87 from warnings import warn |
88 if self._warnings: | |
89 warnings = self._get_db().show_warnings() | |
90 if warnings: | |
91 # This is done in two loops in case | |
92 # Warnings are set to raise exceptions. | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
93 for warning in warnings: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
94 self.messages.append((self.Warning, warning)) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
95 for warning in warnings: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
96 warn(warning[-1], self.Warning, 3) |
0 | 97 elif self._info: |
98 self.messages.append((self.Warning, self._info)) | |
99 warn(self._info, self.Warning, 3) | |
100 | |
101 def nextset(self): | |
102 """Advance to the next result set. | |
103 | |
104 Returns None if there are no more result sets. | |
105 """ | |
106 if self._executed: | |
107 self.fetchall() | |
108 del self.messages[:] | |
109 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
110 connection = self._get_db() |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
111 num_rows = connection.next_result() |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
112 if num_rows == -1: |
0 | 113 return None |
114 self._do_get_result() | |
115 self._post_get_result() | |
116 self._warning_check() | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
117 return True |
0 | 118 |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
119 def _post_get_result(self): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
120 """Stub to be overridden by MixIn.""" |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
121 |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
122 def _get_result(self): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
123 """Stub to be overridden by MixIn.""" |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
124 return [] |
0 | 125 |
126 def _do_get_result(self): | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
127 """Get the result from the last query.""" |
57
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
128 from MySQLdb.converters import lookup_converter |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
129 connection = self._get_db() |
0 | 130 self._result = self._get_result() |
57
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
131 if self._result: |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
132 self.sql_to_python = [ |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
133 lookup_converter(self, f) |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
134 for f in self._result.fields() |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
135 ] |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
136 else: |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
137 self.sql_to_python = [] |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
138 self.rowcount = connection.affected_rows() |
0 | 139 self.rownumber = 0 |
140 self.description = self._result and self._result.describe() or None | |
141 self.description_flags = self._result and self._result.field_flags() or None | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
142 self.lastrowid = connection.insert_id() |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
143 self._warnings = connection.warning_count() |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
144 self._info = connection.info() |
0 | 145 |
146 def setinputsizes(self, *args): | |
147 """Does nothing, required by DB API.""" | |
148 | |
149 def setoutputsizes(self, *args): | |
150 """Does nothing, required by DB API.""" | |
151 | |
152 def _get_db(self): | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
153 """Get the database connection. |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
154 |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
155 Raises ProgrammingError if the connection has been closed.""" |
0 | 156 if not self.connection: |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
157 self.errorhandler(self, self.ProgrammingError, "cursor closed") |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
158 return self.connection._db |
0 | 159 |
160 def execute(self, query, args=None): | |
161 """Execute a query. | |
162 | |
163 query -- string, query to execute on server | |
164 args -- optional sequence or mapping, parameters to use with query. | |
165 | |
166 Note: If args is a sequence, then %s must be used as the | |
167 parameter placeholder in the query. If a mapping is used, | |
168 %(key)s must be used as the placeholder. | |
169 | |
170 Returns long integer rows affected, if any | |
171 | |
172 """ | |
173 del self.messages[:] | |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
174 db = self._get_db() |
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
175 charset = db.character_set_name() |
4 | 176 if isinstance(query, unicode): |
177 query = query.encode(charset) | |
0 | 178 if args is not None: |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
179 query = query % self.connection.literal(args) |
0 | 180 try: |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
181 result = self._query(query) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
182 except TypeError, msg: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
183 if msg.args[0] in ("not enough arguments for format string", |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
184 "not all arguments converted"): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
185 self.messages.append((self.ProgrammingError, msg.args[0])) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
186 self.errorhandler(self, self.ProgrammingError, msg.args[0]) |
0 | 187 else: |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
188 self.messages.append((TypeError, msg)) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
189 self.errorhandler(self, TypeError, msg) |
0 | 190 except: |
54
6e31278d3433
There's no good reason to delay imports when the module is (1) useless without
kylev
parents:
31
diff
changeset
|
191 exc, value, traceback = sys.exc_info() |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
192 del traceback |
0 | 193 self.messages.append((exc, value)) |
194 self.errorhandler(self, exc, value) | |
57
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
195 |
0 | 196 self._executed = query |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
197 if not self._defer_warnings: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
198 self._warning_check() |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
199 return result |
0 | 200 |
201 def executemany(self, query, args): | |
202 """Execute a multi-row query. | |
203 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
204 query |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
205 |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
206 string, query to execute on server |
0 | 207 |
208 args | |
209 | |
210 Sequence of sequences or mappings, parameters to use with | |
211 query. | |
212 | |
213 Returns long integer rows affected, if any. | |
214 | |
215 This method improves performance on multiple-row INSERT and | |
216 REPLACE. Otherwise it is equivalent to looping over args with | |
217 execute(). | |
218 | |
219 """ | |
220 del self.messages[:] | |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
221 db = self._get_db() |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
222 if not args: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
223 return |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
224 charset = self.connection.character_set_name() |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
225 if isinstance(query, unicode): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
226 query = query.encode(charset) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
227 matched = INSERT_VALUES.match(query) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
228 if not matched: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
229 self.rowcount = sum([ self.execute(query, arg) for arg in args ]) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
230 return self.rowcount |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
231 |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
232 start = matched.group('start') |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
233 end = matched.group('end') |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
234 values = matched.group('values') |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
235 |
0 | 236 try: |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
237 sql_params = [ values % self.connection.literal(arg) for arg in args ] |
0 | 238 except TypeError, msg: |
239 if msg.args[0] in ("not enough arguments for format string", | |
240 "not all arguments converted"): | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
241 self.messages.append((self.ProgrammingError, msg.args[0])) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
242 self.errorhandler(self, self.ProgrammingError, msg.args[0]) |
0 | 243 else: |
244 self.messages.append((TypeError, msg)) | |
245 self.errorhandler(self, TypeError, msg) | |
246 except: | |
54
6e31278d3433
There's no good reason to delay imports when the module is (1) useless without
kylev
parents:
31
diff
changeset
|
247 exc, value, traceback = sys.exc_info() |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
248 del traceback |
0 | 249 self.errorhandler(self, exc, value) |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
250 self.rowcount = int(self._query( |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
251 '\n'.join([start, ',\n'.join(sql_params), end, |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
252 ]))) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
253 if not self._defer_warnings: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
254 self._warning_check() |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
255 return self.rowcount |
0 | 256 |
257 def callproc(self, procname, args=()): | |
258 """Execute stored procedure procname with args | |
259 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
260 procname |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
261 string, name of procedure to execute on server |
0 | 262 |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
263 args |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
264 Sequence of parameters to use with procedure |
0 | 265 |
266 Returns the original args. | |
267 | |
268 Compatibility warning: PEP-249 specifies that any modified | |
269 parameters must be returned. This is currently impossible | |
270 as they are only available by storing them in a server | |
271 variable and then retrieved by a query. Since stored | |
272 procedures return zero or more result sets, there is no | |
273 reliable way to get at OUT or INOUT parameters via callproc. | |
274 The server variables are named @_procname_n, where procname | |
275 is the parameter above and n is the position of the parameter | |
276 (from zero). Once all result sets generated by the procedure | |
277 have been fetched, you can issue a SELECT @_procname_0, ... | |
278 query using .execute() to get any OUT or INOUT values. | |
279 | |
280 Compatibility warning: The act of calling a stored procedure | |
281 itself creates an empty result set. This appears after any | |
282 result sets generated by the procedure. This is non-standard | |
283 behavior with respect to the DB-API. Be sure to use nextset() | |
284 to advance through all result sets; otherwise you may get | |
285 disconnected. | |
286 """ | |
287 | |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
288 db = self._get_db() |
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
289 charset = self.connection.character_set_name() |
0 | 290 for index, arg in enumerate(args): |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
291 query = "SET @_%s_%d=%s" % (procname, index, |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
292 self.connection.literal(arg)) |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
293 if isinstance(query, unicode): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
294 query = query.encode(charset) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
295 self._query(query) |
0 | 296 self.nextset() |
297 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
298 query = "CALL %s(%s)" % (procname, |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
299 ','.join(['@_%s_%d' % (procname, i) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
300 for i in range(len(args))])) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
301 if isinstance(query, unicode): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
302 query = query.encode(charset) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
303 self._query(query) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
304 self._executed = query |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
305 if not self._defer_warnings: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
306 self._warning_check() |
0 | 307 return args |
308 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
309 def _do_query(self, query): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
310 """Low-levey query wrapper. Overridden by MixIns.""" |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
311 connection = self._get_db() |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
312 self._executed = query |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
313 connection.query(query) |
0 | 314 self._do_get_result() |
315 return self.rowcount | |
316 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
317 def _query(self, query): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
318 """Hook for _do_query.""" |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
319 return self._do_query(query) |
0 | 320 |
321 def _fetch_row(self, size=1): | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
322 """Low-level fetch_row wrapper.""" |
0 | 323 if not self._result: |
324 return () | |
57
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
325 # unfortunately it is necessary to wrap these generators up as tuples |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
326 # as the rows are expected to be subscriptable. |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
327 return tuple( |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
328 ( |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
329 tuple( ( f(x) for f, x in zip(self.sql_to_python, row) ) ) |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
330 for row in self._result.fetch_row(size, self._fetch_type) |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
331 ) |
9ea2b0e9302e
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
adustman
parents:
54
diff
changeset
|
332 ) |
0 | 333 |
334 def __iter__(self): | |
335 return iter(self.fetchone, None) | |
336 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
337 def fetchone(self): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
338 """Stub to be overridden by a MixIn.""" |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
339 return None |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
340 |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
341 def fetchall(self): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
342 """Stub to be overridden by a MixIn.""" |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
343 return [] |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
344 |
0 | 345 |
346 class CursorStoreResultMixIn(object): | |
347 | |
348 """This is a MixIn class which causes the entire result set to be | |
349 stored on the client side, i.e. it uses mysql_store_result(). If the | |
350 result set can be very large, consider adding a LIMIT clause to your | |
351 query, or using CursorUseResultMixIn instead.""" | |
352 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
353 def _get_result(self): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
354 """Low-level; uses mysql_store_result()""" |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
355 return self._get_db().store_result() |
0 | 356 |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
357 def _query(self, query): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
358 """Low-level; executes query, gets result, and returns rowcount.""" |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
359 rowcount = self._do_query(query) |
0 | 360 self._post_get_result() |
361 return rowcount | |
362 | |
363 def _post_get_result(self): | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
364 """Low-level""" |
0 | 365 self._rows = self._fetch_row(0) |
366 self._result = None | |
367 | |
368 def fetchone(self): | |
369 """Fetches a single row from the cursor. None indicates that | |
370 no more rows are available.""" | |
371 self._check_executed() | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
372 if self.rownumber >= len(self._rows): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
373 return None |
0 | 374 result = self._rows[self.rownumber] |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
375 self.rownumber += 1 |
0 | 376 return result |
377 | |
378 def fetchmany(self, size=None): | |
379 """Fetch up to size rows from the cursor. Result set may be smaller | |
380 than size. If size is not defined, cursor.arraysize is used.""" | |
381 self._check_executed() | |
382 end = self.rownumber + (size or self.arraysize) | |
383 result = self._rows[self.rownumber:end] | |
384 self.rownumber = min(end, len(self._rows)) | |
385 return result | |
386 | |
387 def fetchall(self): | |
388 """Fetchs all available rows from the cursor.""" | |
389 self._check_executed() | |
390 if self.rownumber: | |
391 result = self._rows[self.rownumber:] | |
392 else: | |
393 result = self._rows | |
394 self.rownumber = len(self._rows) | |
395 return result | |
396 | |
397 def scroll(self, value, mode='relative'): | |
398 """Scroll the cursor in the result set to a new position according | |
399 to mode. | |
400 | |
401 If mode is 'relative' (default), value is taken as offset to | |
402 the current position in the result set, if set to 'absolute', | |
403 value states an absolute target position.""" | |
404 self._check_executed() | |
405 if mode == 'relative': | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
406 row = self.rownumber + value |
0 | 407 elif mode == 'absolute': |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
408 row = value |
0 | 409 else: |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
410 self.errorhandler(self, self.ProgrammingError, |
0 | 411 "unknown scroll mode %s" % `mode`) |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
412 if row < 0 or row >= len(self._rows): |
0 | 413 self.errorhandler(self, IndexError, "out of range") |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
414 self.rownumber = row |
0 | 415 |
416 def __iter__(self): | |
417 self._check_executed() | |
418 result = self.rownumber and self._rows[self.rownumber:] or self._rows | |
419 return iter(result) | |
420 | |
421 | |
422 class CursorUseResultMixIn(object): | |
423 | |
424 """This is a MixIn class which causes the result set to be stored | |
425 in the server and sent row-by-row to client side, i.e. it uses | |
426 mysql_use_result(). You MUST retrieve the entire result set and | |
427 close() the cursor before additional queries can be peformed on | |
428 the connection.""" | |
429 | |
4 | 430 _defer_warnings = True |
431 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
432 def _get_result(self): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
433 """Low-level; calls mysql_use_result()""" |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
434 return self._get_db().use_result() |
0 | 435 |
436 def fetchone(self): | |
437 """Fetches a single row from the cursor.""" | |
438 self._check_executed() | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
439 rows = self._fetch_row(1) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
440 if not rows: |
4 | 441 self._warning_check() |
442 return None | |
0 | 443 self.rownumber = self.rownumber + 1 |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
444 return rows[0] |
0 | 445 |
446 def fetchmany(self, size=None): | |
447 """Fetch up to size rows from the cursor. Result set may be smaller | |
448 than size. If size is not defined, cursor.arraysize is used.""" | |
449 self._check_executed() | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
450 rows = self._fetch_row(size or self.arraysize) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
451 self.rownumber = self.rownumber + len(rows) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
452 if not rows: |
4 | 453 self._warning_check() |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
454 return rows |
0 | 455 |
456 def fetchall(self): | |
457 """Fetchs all available rows from the cursor.""" | |
458 self._check_executed() | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
459 rows = self._fetch_row(0) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
460 self.rownumber = self.rownumber + len(rows) |
4 | 461 self._warning_check() |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
462 return rows |
0 | 463 |
464 def __iter__(self): | |
465 return self | |
466 | |
467 def next(self): | |
468 row = self.fetchone() | |
469 if row is None: | |
470 raise StopIteration | |
471 return row | |
472 | |
473 | |
474 class CursorTupleRowsMixIn(object): | |
475 | |
476 """This is a MixIn class that causes all rows to be returned as tuples, | |
477 which is the standard form required by DB API.""" | |
478 | |
479 _fetch_type = 0 | |
480 | |
481 | |
482 class CursorDictRowsMixIn(object): | |
483 | |
484 """This is a MixIn class that causes all rows to be returned as | |
485 dictionaries. This is a non-standard feature.""" | |
486 | |
487 _fetch_type = 1 | |
488 | |
489 | |
490 class Cursor(CursorStoreResultMixIn, CursorTupleRowsMixIn, | |
491 BaseCursor): | |
492 | |
493 """This is the standard Cursor class that returns rows as tuples | |
494 and stores the result set in the client.""" | |
495 | |
496 | |
497 class DictCursor(CursorStoreResultMixIn, CursorDictRowsMixIn, | |
498 BaseCursor): | |
499 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
500 """This is a Cursor class that returns rows as dictionaries and |
0 | 501 stores the result set in the client.""" |
502 | |
503 | |
504 class SSCursor(CursorUseResultMixIn, CursorTupleRowsMixIn, | |
505 BaseCursor): | |
506 | |
507 """This is a Cursor class that returns rows as tuples and stores | |
508 the result set in the server.""" | |
509 | |
510 | |
511 class SSDictCursor(CursorUseResultMixIn, CursorDictRowsMixIn, | |
512 BaseCursor): | |
513 | |
514 """This is a Cursor class that returns rows as dictionaries and | |
515 stores the result set in the server.""" | |
516 | |
517 |