Mercurial > p > mysql-python > mysqldb-2
annotate MySQLdb/cursors.py @ 65:7a60c4574baf MySQLdb
figleaf revealed that the INSERT_VALUES regex never matched. Added a test for this, and fixed the regex (forgot to add group anchors)
author | adustman |
---|---|
date | Sun, 29 Mar 2009 00:52:14 +0000 |
parents | 2d6a35051f64 |
children | 5a7c30cd9de2 |
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 |
65
7a60c4574baf
figleaf revealed that the INSERT_VALUES regex never matched. Added a test for this, and fixed the regex (forgot to add group anchors)
adustman
parents:
64
diff
changeset
|
17 INSERT_VALUES = re.compile(r"(?P<start>.+values\s*)" |
7a60c4574baf
figleaf revealed that the INSERT_VALUES regex never matched. Added a test for this, and fixed the regex (forgot to add group anchors)
adustman
parents:
64
diff
changeset
|
18 r"(?P<values>\(((?<!\\)'[^\)]*?\)[^\)]*(?<!\\)?'|[^\(\)]|(?:\([^\)]*\)))+\))" |
7a60c4574baf
figleaf revealed that the INSERT_VALUES regex never matched. Added a test for this, and fixed the regex (forgot to add group anchors)
adustman
parents:
64
diff
changeset
|
19 r"(?P<end>.*)", re.I) |
0 | 20 |
64
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
21 |
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
22 class Cursor(object): |
0 | 23 |
24 """A base for Cursor classes. Useful attributes: | |
25 | |
26 description | |
27 A tuple of DB API 7-tuples describing the columns in | |
28 the last executed query; see PEP-249 for details. | |
29 | |
30 description_flags | |
31 Tuple of column flags for last query, one entry per column | |
32 in the result set. Values correspond to those in | |
33 MySQLdb.constants.FLAG. See MySQL documentation (C API) | |
34 for more information. Non-standard extension. | |
35 | |
36 arraysize | |
37 default number of rows fetchmany() will fetch | |
38 | |
39 """ | |
40 | |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
41 from MySQLdb.exceptions import MySQLError, Warning, Error, InterfaceError, \ |
0 | 42 DatabaseError, DataError, OperationalError, IntegrityError, \ |
43 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
|
44 |
4 | 45 _defer_warnings = False |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
46 _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
|
47 |
64
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
48 def __init__(self, connection, decoders, encoders): |
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
49 from MySQLdb.converters import default_decoders |
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 | |
64
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
63 self._decoders = decoders |
54
6e31278d3433
There's no good reason to delay imports when the module is (1) useless without
kylev
parents:
31
diff
changeset
|
64 |
0 | 65 def __del__(self): |
66 self.close() | |
67 self.errorhandler = None | |
68 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
|
69 |
0 | 70 def close(self): |
71 """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
|
72 if not self.connection: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
73 return |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
74 try: |
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
75 while self.nextset(): |
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
76 pass |
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
77 except: |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
78 pass |
0 | 79 self.connection = None |
80 | |
81 def _check_executed(self): | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
82 """Ensure that .execute() has been called.""" |
0 | 83 if not self._executed: |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
84 self.errorhandler(self, self.ProgrammingError, "execute() first") |
0 | 85 |
86 def _warning_check(self): | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
87 """Check for warnings, and report via the warnings module.""" |
0 | 88 from warnings import warn |
89 if self._warnings: | |
90 warnings = self._get_db().show_warnings() | |
91 if warnings: | |
92 # This is done in two loops in case | |
93 # 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
|
94 for warning in warnings: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
95 self.messages.append((self.Warning, warning)) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
96 for warning in warnings: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
97 warn(warning[-1], self.Warning, 3) |
0 | 98 elif self._info: |
99 self.messages.append((self.Warning, self._info)) | |
100 warn(self._info, self.Warning, 3) | |
101 | |
102 def nextset(self): | |
103 """Advance to the next result set. | |
104 | |
105 Returns None if there are no more result sets. | |
106 """ | |
107 if self._executed: | |
108 self.fetchall() | |
109 del self.messages[:] | |
110 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
111 connection = self._get_db() |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
112 num_rows = connection.next_result() |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
113 if num_rows == -1: |
0 | 114 return None |
115 self._do_get_result() | |
116 self._post_get_result() | |
117 self._warning_check() | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
118 return True |
0 | 119 |
64
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
120 def _lookup_decoder(self, field): |
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
121 from MySQLdb.converters import filter_NULL |
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
122 for plugin in self._decoders: |
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
123 f = plugin(self, field) |
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
124 if f: |
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
125 return filter_NULL(f) |
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
126 return None # this should never happen |
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
127 |
0 | 128 def _do_get_result(self): |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
129 """Get the result from the last query.""" |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
130 connection = self._get_db() |
0 | 131 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
|
132 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
|
133 self.sql_to_python = [ |
64
2d6a35051f64
Cursor MixIns: DEAD. More of the new type conversion scheme exposed. Two tests failing because encoding hasn't been finished yet.
adustman
parents:
57
diff
changeset
|
134 self._lookup_decoder(f) |
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
|
135 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
|
136 ] |
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 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
|
138 self.sql_to_python = [] |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
139 self.rowcount = connection.affected_rows() |
0 | 140 self.rownumber = 0 |
141 self.description = self._result and self._result.describe() or None | |
142 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
|
143 self.lastrowid = connection.insert_id() |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
144 self._warnings = connection.warning_count() |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
145 self._info = connection.info() |
0 | 146 |
147 def setinputsizes(self, *args): | |
148 """Does nothing, required by DB API.""" | |
149 | |
150 def setoutputsizes(self, *args): | |
151 """Does nothing, required by DB API.""" | |
152 | |
153 def _get_db(self): | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
154 """Get the database connection. |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
155 |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
156 Raises ProgrammingError if the connection has been closed.""" |
0 | 157 if not self.connection: |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
158 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
|
159 return self.connection._db |
0 | 160 |
161 def execute(self, query, args=None): | |
162 """Execute a query. | |
163 | |
164 query -- string, query to execute on server | |
165 args -- optional sequence or mapping, parameters to use with query. | |
166 | |
167 Note: If args is a sequence, then %s must be used as the | |
168 parameter placeholder in the query. If a mapping is used, | |
169 %(key)s must be used as the placeholder. | |
170 | |
171 Returns long integer rows affected, if any | |
172 | |
173 """ | |
174 del self.messages[:] | |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
175 db = self._get_db() |
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
176 charset = db.character_set_name() |
4 | 177 if isinstance(query, unicode): |
178 query = query.encode(charset) | |
0 | 179 if args is not None: |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
180 query = query % self.connection.literal(args) |
0 | 181 try: |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
182 result = self._query(query) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
183 except TypeError, msg: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
184 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
|
185 "not all arguments converted"): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
186 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
|
187 self.errorhandler(self, self.ProgrammingError, msg.args[0]) |
0 | 188 else: |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
189 self.messages.append((TypeError, msg)) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
190 self.errorhandler(self, TypeError, msg) |
0 | 191 except: |
54
6e31278d3433
There's no good reason to delay imports when the module is (1) useless without
kylev
parents:
31
diff
changeset
|
192 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
|
193 del traceback |
0 | 194 self.messages.append((exc, value)) |
195 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
|
196 |
0 | 197 self._executed = query |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
198 if not self._defer_warnings: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
199 self._warning_check() |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
200 return result |
0 | 201 |
202 def executemany(self, query, args): | |
203 """Execute a multi-row query. | |
204 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
205 query |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
206 |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
207 string, query to execute on server |
0 | 208 |
209 args | |
210 | |
211 Sequence of sequences or mappings, parameters to use with | |
212 query. | |
213 | |
214 Returns long integer rows affected, if any. | |
215 | |
216 This method improves performance on multiple-row INSERT and | |
217 REPLACE. Otherwise it is equivalent to looping over args with | |
218 execute(). | |
219 | |
220 """ | |
221 del self.messages[:] | |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
222 db = self._get_db() |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
223 if not args: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
224 return |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
225 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
|
226 if isinstance(query, unicode): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
227 query = query.encode(charset) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
228 matched = INSERT_VALUES.match(query) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
229 if not matched: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
230 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
|
231 return self.rowcount |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
232 |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
233 start = matched.group('start') |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
234 end = matched.group('end') |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
235 values = matched.group('values') |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
236 |
0 | 237 try: |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
238 sql_params = [ values % self.connection.literal(arg) for arg in args ] |
0 | 239 except TypeError, msg: |
240 if msg.args[0] in ("not enough arguments for format string", | |
241 "not all arguments converted"): | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
242 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
|
243 self.errorhandler(self, self.ProgrammingError, msg.args[0]) |
0 | 244 else: |
245 self.messages.append((TypeError, msg)) | |
246 self.errorhandler(self, TypeError, msg) | |
247 except: | |
54
6e31278d3433
There's no good reason to delay imports when the module is (1) useless without
kylev
parents:
31
diff
changeset
|
248 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
|
249 del traceback |
0 | 250 self.errorhandler(self, exc, value) |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
251 self.rowcount = int(self._query( |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
252 '\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
|
253 ]))) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
254 if not self._defer_warnings: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
255 self._warning_check() |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
256 return self.rowcount |
0 | 257 |
258 def callproc(self, procname, args=()): | |
259 """Execute stored procedure procname with args | |
260 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
261 procname |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
262 string, name of procedure to execute on server |
0 | 263 |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
264 args |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
265 Sequence of parameters to use with procedure |
0 | 266 |
267 Returns the original args. | |
268 | |
269 Compatibility warning: PEP-249 specifies that any modified | |
270 parameters must be returned. This is currently impossible | |
271 as they are only available by storing them in a server | |
272 variable and then retrieved by a query. Since stored | |
273 procedures return zero or more result sets, there is no | |
274 reliable way to get at OUT or INOUT parameters via callproc. | |
275 The server variables are named @_procname_n, where procname | |
276 is the parameter above and n is the position of the parameter | |
277 (from zero). Once all result sets generated by the procedure | |
278 have been fetched, you can issue a SELECT @_procname_0, ... | |
279 query using .execute() to get any OUT or INOUT values. | |
280 | |
281 Compatibility warning: The act of calling a stored procedure | |
282 itself creates an empty result set. This appears after any | |
283 result sets generated by the procedure. This is non-standard | |
284 behavior with respect to the DB-API. Be sure to use nextset() | |
285 to advance through all result sets; otherwise you may get | |
286 disconnected. | |
287 """ | |
288 | |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
289 db = self._get_db() |
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
290 charset = self.connection.character_set_name() |
0 | 291 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
|
292 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
|
293 self.connection.literal(arg)) |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
294 if isinstance(query, unicode): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
295 query = query.encode(charset) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
296 self._query(query) |
0 | 297 self.nextset() |
298 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
299 query = "CALL %s(%s)" % (procname, |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
300 ','.join(['@_%s_%d' % (procname, i) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
301 for i in range(len(args))])) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
302 if isinstance(query, unicode): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
303 query = query.encode(charset) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
304 self._query(query) |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
305 self._executed = query |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
306 if not self._defer_warnings: |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
307 self._warning_check() |
0 | 308 return args |
309 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
310 def _do_query(self, query): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
311 """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
|
312 connection = self._get_db() |
18
d55bfb1a4701
Tons of changes from major refactoring/cleanup. This is all really broken
adustman
parents:
14
diff
changeset
|
313 self._executed = query |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
314 connection.query(query) |
0 | 315 self._do_get_result() |
316 return self.rowcount | |
317 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
318 def _query(self, query): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
319 """Hook for _do_query.""" |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
320 return self._do_query(query) |
0 | 321 |
322 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
|
323 """Low-level fetch_row wrapper.""" |
0 | 324 if not self._result: |
325 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
|
326 # 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
|
327 # 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
|
328 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
|
329 ( |
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 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
|
331 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
|
332 ) |
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
|
333 ) |
0 | 334 |
335 def __iter__(self): | |
336 return iter(self.fetchone, None) | |
337 | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
338 def _get_result(self): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
339 """Low-level; uses mysql_store_result()""" |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
340 return self._get_db().store_result() |
0 | 341 |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
342 def _query(self, query): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
343 """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
|
344 rowcount = self._do_query(query) |
0 | 345 self._post_get_result() |
346 return rowcount | |
347 | |
348 def _post_get_result(self): | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
349 """Low-level""" |
0 | 350 self._rows = self._fetch_row(0) |
351 self._result = None | |
352 | |
353 def fetchone(self): | |
354 """Fetches a single row from the cursor. None indicates that | |
355 no more rows are available.""" | |
356 self._check_executed() | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
357 if self.rownumber >= len(self._rows): |
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
358 return None |
0 | 359 result = self._rows[self.rownumber] |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
360 self.rownumber += 1 |
0 | 361 return result |
362 | |
363 def fetchmany(self, size=None): | |
364 """Fetch up to size rows from the cursor. Result set may be smaller | |
365 than size. If size is not defined, cursor.arraysize is used.""" | |
366 self._check_executed() | |
367 end = self.rownumber + (size or self.arraysize) | |
368 result = self._rows[self.rownumber:end] | |
369 self.rownumber = min(end, len(self._rows)) | |
370 return result | |
371 | |
372 def fetchall(self): | |
373 """Fetchs all available rows from the cursor.""" | |
374 self._check_executed() | |
375 if self.rownumber: | |
376 result = self._rows[self.rownumber:] | |
377 else: | |
378 result = self._rows | |
379 self.rownumber = len(self._rows) | |
380 return result | |
381 | |
382 def scroll(self, value, mode='relative'): | |
383 """Scroll the cursor in the result set to a new position according | |
384 to mode. | |
385 | |
386 If mode is 'relative' (default), value is taken as offset to | |
387 the current position in the result set, if set to 'absolute', | |
388 value states an absolute target position.""" | |
389 self._check_executed() | |
390 if mode == 'relative': | |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
391 row = self.rownumber + value |
0 | 392 elif mode == 'absolute': |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
393 row = value |
0 | 394 else: |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
395 self.errorhandler(self, self.ProgrammingError, |
0 | 396 "unknown scroll mode %s" % `mode`) |
10
3f4c6af70e52
Me and PyLint had a knife fight, but PyLint had a gun.
adustman
parents:
8
diff
changeset
|
397 if row < 0 or row >= len(self._rows): |
0 | 398 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
|
399 self.rownumber = row |
0 | 400 |
401 def __iter__(self): | |
402 self._check_executed() | |
403 result = self.rownumber and self._rows[self.rownumber:] or self._rows | |
404 return iter(result) | |
405 | |
406 _fetch_type = 0 |