Skip to content

Commit 2511c7e

Browse files
committed
Merge pull request #69 from methane/feature/faster-surrogateescape
faster surrogateescape
2 parents 5d91470 + 6ff138a commit 2511c7e

File tree

2 files changed

+26
-24
lines changed

2 files changed

+26
-24
lines changed

MySQLdb/connections.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
"""
2-
32
This module implements connections for MySQLdb. Presently there is
43
only one class: Connection. Others are unlikely. However, you might
54
want to make your own subclasses. In most cases, you will probably
65
override Connection.default_cursor with a non-standard Cursor class.
7-
86
"""
97
from MySQLdb import cursors
108
from MySQLdb.compat import unicode, PY2
@@ -15,6 +13,14 @@
1513
import re
1614

1715

16+
if not PY2:
17+
# See http://bugs.python.org/issue24870
18+
_surrogateescape_table = [chr(i) if i < 0x80 else chr(i + 0xdc00) for i in range(256)]
19+
20+
def _fast_surroundescape(s):
21+
return s.decode('latin1').translate(_surrogateescape_table)
22+
23+
1824
def defaulterrorhandler(connection, cursor, errorclass, errorvalue):
1925
"""
2026
If cursor is not None, (errorclass, errorvalue) is appended to
@@ -34,7 +40,7 @@ def defaulterrorhandler(connection, cursor, errorclass, errorvalue):
3440
del connection
3541
if isinstance(errorvalue, BaseException):
3642
raise errorvalue
37-
if errorclass is not None:
43+
if errorclass is not None:
3844
raise errorclass(errorvalue)
3945
else:
4046
raise Exception(errorvalue)
@@ -291,24 +297,21 @@ def __exit__(self, exc, value, tb):
291297
self.commit()
292298

293299
def literal(self, o):
294-
"""
295-
296-
If o is a single object, returns an SQL literal as a string.
300+
"""If o is a single object, returns an SQL literal as a string.
297301
If o is a non-string sequence, the items of the sequence are
298302
converted and returned as a sequence.
299303
300304
Non-standard. For internal use; do not use this in your
301305
applications.
302-
303306
"""
304307
s = self.escape(o, self.encoders)
305-
# Python 3 doesn't support % operation for bytes object.
308+
# Python 3(~3.4) doesn't support % operation for bytes object.
306309
# We should decode it before using %.
307310
# Decoding with ascii and surrogateescape allows convert arbitrary
308311
# bytes to unicode and back again.
309312
# See http://python.org/dev/peps/pep-0383/
310-
if not PY2 and isinstance(s, bytes):
311-
return s.decode('ascii', 'surrogateescape')
313+
if not PY2 and isinstance(s, (bytes, bytearray)):
314+
return _fast_surroundescape(s)
312315
return s
313316

314317
def begin(self):

MySQLdb/cursors.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def execute(self, query, args=None):
187187
parameter placeholder in the query. If a mapping is used,
188188
%(key)s must be used as the placeholder.
189189
190-
Returns long integer rows affected, if any
190+
Returns integer represents rows affected, if any
191191
"""
192192
while self.nextset():
193193
pass
@@ -208,27 +208,25 @@ def execute(self, query, args=None):
208208
args = dict((key, db.literal(item)) for key, item in args.items())
209209
else:
210210
args = tuple(map(db.literal, args))
211-
if not PY2 and isinstance(query, bytes):
211+
if not PY2 and isinstance(query, (bytes, bytearray)):
212212
query = query.decode(db.unicode_literal.charset)
213-
query = query % args
213+
try:
214+
query = query % args
215+
except TypeError as m:
216+
self.errorhandler(self, ProgrammingError, str(m))
214217

215218
if isinstance(query, unicode):
216219
query = query.encode(db.unicode_literal.charset, 'surrogateescape')
217220

218221
res = None
219222
try:
220223
res = self._query(query)
221-
except TypeError as m:
222-
if m.args[0] in ("not enough arguments for format string",
223-
"not all arguments converted"):
224-
self.errorhandler(self, ProgrammingError, m.args[0])
225-
else:
226-
self.errorhandler(self, TypeError, m)
227224
except Exception:
228225
exc, value = sys.exc_info()[:2]
229226
self.errorhandler(self, exc, value)
230227
self._executed = query
231-
if not self._defer_warnings: self._warning_check()
228+
if not self._defer_warnings:
229+
self._warning_check()
232230
return res
233231

234232
def executemany(self, query, args):
@@ -369,13 +367,13 @@ def __iter__(self):
369367

370368

371369
class CursorStoreResultMixIn(object):
372-
373370
"""This is a MixIn class which causes the entire result set to be
374371
stored on the client side, i.e. it uses mysql_store_result(). If the
375372
result set can be very large, consider adding a LIMIT clause to your
376373
query, or using CursorUseResultMixIn instead."""
377374

378-
def _get_result(self): return self._get_db().store_result()
375+
def _get_result(self):
376+
return self._get_db().store_result()
379377

380378
def _query(self, q):
381379
rowcount = self._do_query(q)
@@ -390,9 +388,10 @@ def fetchone(self):
390388
"""Fetches a single row from the cursor. None indicates that
391389
no more rows are available."""
392390
self._check_executed()
393-
if self.rownumber >= len(self._rows): return None
391+
if self.rownumber >= len(self._rows):
392+
return None
394393
result = self._rows[self.rownumber]
395-
self.rownumber = self.rownumber+1
394+
self.rownumber = self.rownumber + 1
396395
return result
397396

398397
def fetchmany(self, size=None):

0 commit comments

Comments
 (0)