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