18
18
19
19
from .charset import MBLENGTH , charset_by_name , charset_by_id
20
20
from .constants import CLIENT , COMMAND , CR , FIELD_TYPE , SERVER_STATUS
21
- from .converters import escape_item , escape_string , through , conversions as _conv
21
+ from . import converters
22
22
from .cursors import Cursor
23
23
from .optionfile import Parser
24
24
from .util import byte2int , int2byte
44
44
45
45
_py_version = sys .version_info [:2 ]
46
46
47
+ if PY2 :
48
+ pass
49
+ elif _py_version < (3 , 6 ):
50
+ # See http://bugs.python.org/issue24870
51
+ _surrogateescape_table = [chr (i ) if i < 0x80 else chr (i + 0xdc00 ) for i in range (256 )]
52
+
53
+ def _fast_surrogateescape (s ):
54
+ return s .decode ('latin1' ).translate (_surrogateescape_table )
55
+ else :
56
+ def _fast_surrogateescape (s ):
57
+ return s .decode ('ascii' , 'surrogateescape' )
47
58
48
59
# socket.makefile() in Python 2 is not usable because very inefficient and
49
60
# bad behavior about timeout.
50
61
# XXX: ._socketio doesn't work under IronPython.
51
- if _py_version == ( 2 , 7 ) and not IRONPYTHON :
62
+ if PY2 and not IRONPYTHON :
52
63
# read method of file-like returned by sock.makefile() is very slow.
53
64
# So we copy io-based one from Python 3.
54
65
from ._socketio import SocketIO
55
66
56
67
def _makefile (sock , mode ):
57
68
return io .BufferedReader (SocketIO (sock , mode ))
58
- elif _py_version == (2 , 6 ):
59
- # Python 2.6 doesn't have fast io module.
60
- # So we make original one.
61
- class SockFile (object ):
62
- def __init__ (self , sock ):
63
- self ._sock = sock
64
-
65
- def read (self , n ):
66
- read = self ._sock .recv (n )
67
- if len (read ) == n :
68
- return read
69
- while True :
70
- data = self ._sock .recv (n - len (read ))
71
- if not data :
72
- return read
73
- read += data
74
- if len (read ) == n :
75
- return read
76
-
77
- def _makefile (sock , mode ):
78
- assert mode == 'rb'
79
- return SockFile (sock )
80
69
else :
81
70
# socket.makefile in Python 3 is nice.
82
71
def _makefile (sock , mode ):
@@ -570,6 +559,7 @@ class Connection(object):
570
559
(if no authenticate method) for returning a string from the user. (experimental)
571
560
:param db: Alias for database. (for compatibility to MySQLdb)
572
561
:param passwd: Alias for password. (for compatibility to MySQLdb)
562
+ :param binary_prefix: Add _binary prefix on bytes and bytearray. (default: False)
573
563
"""
574
564
575
565
_sock = None
@@ -586,7 +576,7 @@ def __init__(self, host=None, user=None, password="",
586
576
autocommit = False , db = None , passwd = None , local_infile = False ,
587
577
max_allowed_packet = 16 * 1024 * 1024 , defer_connect = False ,
588
578
auth_plugin_map = {}, read_timeout = None , write_timeout = None ,
589
- bind_address = None ):
579
+ bind_address = None , binary_prefix = False ):
590
580
if no_delay is not None :
591
581
warnings .warn ("no_delay option is deprecated" , DeprecationWarning )
592
582
@@ -693,14 +683,16 @@ def _config(key, arg):
693
683
self .autocommit_mode = autocommit
694
684
695
685
if conv is None :
696
- conv = _conv
686
+ conv = converters .conversions
687
+
697
688
# Need for MySQLdb compatibility.
698
689
self .encoders = dict ([(k , v ) for (k , v ) in conv .items () if type (k ) is not int ])
699
690
self .decoders = dict ([(k , v ) for (k , v ) in conv .items () if type (k ) is int ])
700
691
self .sql_mode = sql_mode
701
692
self .init_command = init_command
702
693
self .max_allowed_packet = max_allowed_packet
703
694
self ._auth_plugin_map = auth_plugin_map
695
+ self ._binary_prefix = binary_prefix
704
696
if defer_connect :
705
697
self ._sock = None
706
698
else :
@@ -812,7 +804,12 @@ def escape(self, obj, mapping=None):
812
804
"""
813
805
if isinstance (obj , str_type ):
814
806
return "'" + self .escape_string (obj ) + "'"
815
- return escape_item (obj , self .charset , mapping = mapping )
807
+ if isinstance (obj , (bytes , bytearray )):
808
+ ret = self ._quote_bytes (obj )
809
+ if self ._binary_prefix :
810
+ ret = "_binary" + ret
811
+ return ret
812
+ return converters .escape_item (obj , self .charset , mapping = mapping )
816
813
817
814
def literal (self , obj ):
818
815
"""Alias for escape()
@@ -825,7 +822,13 @@ def escape_string(self, s):
825
822
if (self .server_status &
826
823
SERVER_STATUS .SERVER_STATUS_NO_BACKSLASH_ESCAPES ):
827
824
return s .replace ("'" , "''" )
828
- return escape_string (s )
825
+ return converters .escape_string (s )
826
+
827
+ def _quote_bytes (self , s ):
828
+ if (self .server_status &
829
+ SERVER_STATUS .SERVER_STATUS_NO_BACKSLASH_ESCAPES ):
830
+ return "'%s'" % (_fast_surrogateescape (s .replace (b"'" , b"''" )),)
831
+ return converters .escape_bytes (s )
829
832
830
833
def cursor (self , cursor = None ):
831
834
"""Create a new cursor to execute queries with"""
@@ -1510,7 +1513,7 @@ def _get_descriptions(self):
1510
1513
else :
1511
1514
encoding = None
1512
1515
converter = self .connection .decoders .get (field_type )
1513
- if converter is through :
1516
+ if converter is converters . through :
1514
1517
converter = None
1515
1518
if DEBUG : print ("DEBUG: field={}, converter={}" .format (field , converter ))
1516
1519
self .converters .append ((encoding , converter ))
0 commit comments