From c139119e65168237fb0a061007e8b0b5b96859a2 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Fri, 8 Jan 2016 22:02:24 +0900 Subject: [PATCH] Add _binary prefix for binaries. On Python 2, bytearray represents binary data. On Python 3, bytes and bytearray represents binary data. reference: https://github.com/go-sql-driver/mysql/pull/382 https://dev.mysql.com/doc/relnotes/mysql/5.5/en/news-5-5-46.html https://dev.mysql.com/doc/relnotes/mysql/5.6/en/news-5-6-27.html --- pymysql/__init__.py | 9 ++++--- pymysql/converters.py | 48 ++++++++++++++++++++++-------------- pymysql/tests/test_issues.py | 4 +-- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/pymysql/__init__.py b/pymysql/__init__.py index dff5efc..1aa8fc7 100644 --- a/pymysql/__init__.py +++ b/pymysql/__init__.py @@ -25,7 +25,7 @@ THE SOFTWARE. VERSION = (0, 6, 7, None) -from ._compat import text_type, JYTHON, IRONPYTHON +from ._compat import text_type, JYTHON, IRONPYTHON, PY2 from .constants import FIELD_TYPE from .converters import escape_dict, escape_sequence, escape_string from .err import Warning, Error, InterfaceError, DataError, \ @@ -76,8 +76,11 @@ ROWID = DBAPISet() def Binary(x): """Return x as a binary type.""" if isinstance(x, text_type) and not (JYTHON or IRONPYTHON): - return x.encode() - return bytes(x) + x = x.encode() + if PY2: + return bytearray(x) + else: + return bytes(x) def Connect(*args, **kwargs): """ diff --git a/pymysql/converters.py b/pymysql/converters.py index 1e97dc2..0ffb1e6 100644 --- a/pymysql/converters.py +++ b/pymysql/converters.py @@ -57,12 +57,31 @@ def escape_int(value, mapping=None): def escape_float(value, mapping=None): return ('%.15g' % value) +_escape_table = [chr(x) for x in range(128)] +_escape_table[0] = u'\\0' +_escape_table[ord('\\')] = u'\\\\' +_escape_table[ord('\n')] = u'\\n' +_escape_table[ord('\r')] = u'\\r' +_escape_table[ord('\032')] = u'\\Z' +_escape_table[ord('"')] = u'\\"' +_escape_table[ord("'")] = u"\\'" + +def _escape_unicode(value, mapping=None): + """escapes *value* without adding quote. + + Value should be unicode + """ + return value.translate(_escape_table) + if PY2: def escape_string(value, mapping=None): """escape_string escapes *value* but not surround it with quotes. Value should be bytes or unicode. """ + if isinstance(value, unicode): + return escape_unicode(value) + assert isinstance(value, bytes) value = value.replace('\\', '\\\\') value = value.replace('\0', '\\0') value = value.replace('\n', '\\n') @@ -71,22 +90,12 @@ if PY2: value = value.replace("'", "\\'") value = value.replace('"', '\\"') return value + + def escape_bytes(value, mapping=None): + assert isinstance(value, (bytes, bytearray)) + return b"_binary'%s'" % value else: - _escape_table = [chr(x) for x in range(128)] - _escape_table[0] = '\\0' - _escape_table[ord('\\')] = '\\\\' - _escape_table[ord('\n')] = '\\n' - _escape_table[ord('\r')] = '\\r' - _escape_table[ord('\032')] = '\\Z' - _escape_table[ord('"')] = '\\"' - _escape_table[ord("'")] = "\\'" - - def escape_string(value, mapping=None): - """escape_string escapes *value* but not surround it with quotes. - - Value should be str (unicode). - """ - return value.translate(_escape_table) + escape_string = _escape_unicode # On Python ~3.5, str.decode('ascii', 'surrogateescape') is slow. # (fixed in Python 3.6, http://bugs.python.org/issue24870) @@ -95,15 +104,15 @@ else: _escape_bytes_table = _escape_table + [chr(i) for i in range(0xdc80, 0xdd00)] def escape_bytes(value, mapping=None): - return "'%s'" % value.decode('latin1').translate(_escape_bytes_table) + return "_binary'%s'" % value.decode('latin1').translate(_escape_bytes_table) +def escape_unicode(value, mapping=None): + return u"'%s'" % _escape_unicode(value) + def escape_str(value, mapping=None): return "'%s'" % escape_string(value, mapping) -def escape_unicode(value, mapping=None): - return escape_str(value, mapping) - def escape_None(value, mapping=None): return 'NULL' @@ -337,6 +346,7 @@ encoders = { list: escape_sequence, set: escape_sequence, dict: escape_dict, + bytearray: escape_bytes, type(None): escape_None, datetime.date: escape_date, datetime.datetime: escape_datetime, diff --git a/pymysql/tests/test_issues.py b/pymysql/tests/test_issues.py index 5ec65d8..02334c2 100644 --- a/pymysql/tests/test_issues.py +++ b/pymysql/tests/test_issues.py @@ -413,8 +413,8 @@ class TestGitHubIssues(base.PyMySQLTestCase): "create table issue364 (value_1 binary(3), value_2 varchar(3)) " "engine=InnoDB default charset=utf8") - sql = "insert into issue364 (value_1, value_2) values (_binary%s, _binary%s)" - usql = u"insert into issue364 (value_1, value_2) values (_binary%s, _binary%s)" + sql = "insert into issue364 (value_1, value_2) values (%s, %s)" + usql = u"insert into issue364 (value_1, value_2) values (%s, %s)" values = [b"\x00\xff\x00", u"\xe4\xf6\xfc"] # test single insert and select