Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit cba486e

Browse filesBrowse files
vtermanismethane
authored andcommitted
Use _binary prefix for bytes/bytearray parameters (PyMySQL#140)
- Based on PyMySQL#106 but now disabled by default - Can be enabled via 'binary_prefix' connection parameter - Added unit tests to verify behaviour
1 parent 50a81b1 commit cba486e
Copy full SHA for cba486e

File tree

Expand file treeCollapse file tree

3 files changed

+46
-6
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+46
-6
lines changed

‎MySQLdb/__init__.py

Copy file name to clipboardExpand all lines: MySQLdb/__init__.py
+7-2Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
paramstyle = "format"
2828

2929
from _mysql import *
30+
from MySQLdb.compat import PY2
3031
from MySQLdb.constants import FIELD_TYPE
3132
from MySQLdb.times import Date, Time, Timestamp, \
3233
DateFromTicks, TimeFromTicks, TimestampFromTicks
@@ -72,8 +73,12 @@ def test_DBAPISet_set_equality_membership():
7273
def test_DBAPISet_set_inequality_membership():
7374
assert FIELD_TYPE.DATE != STRING
7475

75-
def Binary(x):
76-
return bytes(x)
76+
if PY2:
77+
def Binary(x):
78+
return bytearray(x)
79+
else:
80+
def Binary(x):
81+
return bytes(x)
7782

7883
def Connect(*args, **kwargs):
7984
"""Factory function for connections.Connection."""

‎MySQLdb/connections.py

Copy file name to clipboardExpand all lines: MySQLdb/connections.py
+20-4Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ class object, used to create cursors (keyword only)
137137
If True, autocommit is enabled.
138138
If None, autocommit isn't set and server default is used.
139139
140+
:param bool binary_prefix:
141+
If set, the '_binary' prefix will be used for raw byte query
142+
arguments (e.g. Binary). This is disabled by default.
143+
140144
There are a number of undocumented, non-standard methods. See the
141145
documentation for the MySQL C API for some hints on what they do.
142146
"""
@@ -174,6 +178,7 @@ class object, used to create cursors (keyword only)
174178

175179
use_unicode = kwargs2.pop('use_unicode', use_unicode)
176180
sql_mode = kwargs2.pop('sql_mode', '')
181+
binary_prefix = kwargs2.pop('binary_prefix', False)
177182

178183
client_flag = kwargs.get('client_flag', 0)
179184
client_version = tuple([ numeric_part(n) for n in _mysql.get_client_info().split('.')[:2] ])
@@ -197,7 +202,7 @@ class object, used to create cursors (keyword only)
197202

198203
db = proxy(self)
199204
def _get_string_literal():
200-
# Note: string_literal() is called for bytes object on Python 3.
205+
# Note: string_literal() is called for bytes object on Python 3 (via bytes_literal)
201206
def string_literal(obj, dummy=None):
202207
return db.string_literal(obj)
203208
return string_literal
@@ -206,20 +211,26 @@ def _get_unicode_literal():
206211
if PY2:
207212
# unicode_literal is called for only unicode object.
208213
def unicode_literal(u, dummy=None):
209-
return db.literal(u.encode(unicode_literal.charset))
214+
return db.string_literal(u.encode(unicode_literal.charset))
210215
else:
211216
# unicode_literal() is called for arbitrary object.
212217
def unicode_literal(u, dummy=None):
213-
return db.literal(str(u).encode(unicode_literal.charset))
218+
return db.string_literal(str(u).encode(unicode_literal.charset))
214219
return unicode_literal
215220

221+
def _get_bytes_literal():
222+
def bytes_literal(obj, dummy=None):
223+
return b'_binary' + db.string_literal(obj)
224+
return bytes_literal
225+
216226
def _get_string_decoder():
217227
def string_decoder(s):
218228
return s.decode(string_decoder.charset)
219229
return string_decoder
220230

221231
string_literal = _get_string_literal()
222232
self.unicode_literal = unicode_literal = _get_unicode_literal()
233+
bytes_literal = _get_bytes_literal()
223234
self.string_decoder = string_decoder = _get_string_decoder()
224235
if not charset:
225236
charset = self.character_set_name()
@@ -234,7 +245,12 @@ def string_decoder(s):
234245
self.converter[FIELD_TYPE.VARCHAR].append((None, string_decoder))
235246
self.converter[FIELD_TYPE.BLOB].append((None, string_decoder))
236247

237-
self.encoders[bytes] = string_literal
248+
if binary_prefix:
249+
self.encoders[bytes] = string_literal if PY2 else bytes_literal
250+
self.encoders[bytearray] = bytes_literal
251+
else:
252+
self.encoders[bytes] = string_literal
253+
238254
self.encoders[unicode] = unicode_literal
239255
self._transactional = self.server_capabilities & CLIENT.TRANSACTIONS
240256
if self._transactional:

‎tests/test_MySQLdb_capabilities.py

Copy file name to clipboardExpand all lines: tests/test_MySQLdb_capabilities.py
+19Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
# -*- coding: utf-8 -*-
33
import capabilities
44
from datetime import timedelta
5+
from contextlib import closing
56
import unittest
67
import MySQLdb
78
from MySQLdb.compat import unicode
89
from MySQLdb import cursors
10+
from configdb import connection_factory
911
import warnings
1012

1113

@@ -180,6 +182,23 @@ def test_warning_propagation(self):
180182
finally:
181183
c.close()
182184

185+
def test_binary_prefix(self):
186+
# verify prefix behaviour when enabled, disabled and for default (disabled)
187+
for binary_prefix in (True, False, None):
188+
kwargs = self.connect_kwargs.copy()
189+
# needs to be set to can guarantee CHARSET response for normal strings
190+
kwargs['charset'] = 'utf8'
191+
if binary_prefix != None:
192+
kwargs['binary_prefix'] = binary_prefix
193+
194+
with closing(connection_factory(**kwargs)) as conn:
195+
with closing(conn.cursor()) as c:
196+
c.execute('SELECT CHARSET(%s)', (MySQLdb.Binary(b'raw bytes'),))
197+
self.assertEqual(c.fetchall()[0][0], 'binary' if binary_prefix else 'utf8')
198+
# normal strings should not get prefix
199+
c.execute('SELECT CHARSET(%s)', ('str',))
200+
self.assertEqual(c.fetchall()[0][0], 'utf8')
201+
183202

184203
if __name__ == '__main__':
185204
if test_MySQLdb.leak_test:

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.