17
17
import warnings
18
18
19
19
from .charset import MBLENGTH , charset_by_name , charset_by_id
20
- from .constants import CLIENT , COMMAND , FIELD_TYPE , SERVER_STATUS
20
+ from .constants import CLIENT , COMMAND , CR , FIELD_TYPE , SERVER_STATUS
21
21
from .converters import escape_item , escape_string , through , conversions as _conv
22
22
from .cursors import Cursor
23
23
from .optionfile import Parser
@@ -524,6 +524,7 @@ class Connection(object):
524
524
525
525
_sock = None
526
526
_auth_plugin_name = ''
527
+ _closed = False
527
528
528
529
def __init__ (self , host = None , user = None , password = "" ,
529
530
database = None , port = 0 , unix_socket = None ,
@@ -715,8 +716,11 @@ def _create_ssl_ctx(self, sslp):
715
716
716
717
def close (self ):
717
718
"""Send the quit message and close the socket"""
718
- if self ._sock is None :
719
+ if self ._closed :
719
720
raise err .Error ("Already closed" )
721
+ self ._closed = True
722
+ if self ._sock is None :
723
+ return
720
724
send_data = struct .pack ('<iB' , 1 , COMMAND .COM_QUIT )
721
725
try :
722
726
self ._write_bytes (send_data )
@@ -732,7 +736,8 @@ def close(self):
732
736
def open (self ):
733
737
return self ._sock is not None
734
738
735
- def __del__ (self ):
739
+ def _force_close (self ):
740
+ """Close connection without QUIT message"""
736
741
if self ._sock :
737
742
try :
738
743
self ._sock .close ()
@@ -741,6 +746,8 @@ def __del__(self):
741
746
self ._sock = None
742
747
self ._rfile = None
743
748
749
+ __del__ = _force_close
750
+
744
751
def autocommit (self , value ):
745
752
self .autocommit_mode = bool (value )
746
753
current = self .get_autocommit ()
@@ -884,6 +891,7 @@ def set_charset(self, charset):
884
891
self .encoding = encoding
885
892
886
893
def connect (self , sock = None ):
894
+ self ._closed = False
887
895
try :
888
896
if sock is None :
889
897
if self .unix_socket and self .host in ('localhost' , '127.0.0.1' ):
@@ -977,8 +985,15 @@ def _read_packet(self, packet_type=MysqlPacket):
977
985
btrl , btrh , packet_number = struct .unpack ('<HBB' , packet_header )
978
986
bytes_to_read = btrl + (btrh << 16 )
979
987
if packet_number != self ._next_seq_id :
980
- raise err .InternalError ("Packet sequence number wrong - got %d expected %d" %
981
- (packet_number , self ._next_seq_id ))
988
+ self ._force_close ()
989
+ if packet_number == 0 :
990
+ # MariaDB sends error packet with seqno==0 when shutdown
991
+ raise err .OperationalError (
992
+ CR .CR_SERVER_LOST ,
993
+ "Lost connection to MySQL server during query" )
994
+ raise err .InternalError (
995
+ "Packet sequence number wrong - got %d expected %d"
996
+ % (packet_number , self ._next_seq_id ))
982
997
self ._next_seq_id = (self ._next_seq_id + 1 ) % 256
983
998
984
999
recv_data = self ._read_bytes (bytes_to_read )
@@ -1003,20 +1018,25 @@ def _read_bytes(self, num_bytes):
1003
1018
except (IOError , OSError ) as e :
1004
1019
if e .errno == errno .EINTR :
1005
1020
continue
1021
+ self ._force_close ()
1006
1022
raise err .OperationalError (
1007
- 2013 ,
1023
+ CR . CR_SERVER_LOST ,
1008
1024
"Lost connection to MySQL server during query (%s)" % (e ,))
1009
1025
if len (data ) < num_bytes :
1026
+ self ._force_close ()
1010
1027
raise err .OperationalError (
1011
- 2013 , "Lost connection to MySQL server during query" )
1028
+ CR . CR_SERVER_LOST , "Lost connection to MySQL server during query" )
1012
1029
return data
1013
1030
1014
1031
def _write_bytes (self , data ):
1015
1032
self ._sock .settimeout (self ._write_timeout )
1016
1033
try :
1017
1034
self ._sock .sendall (data )
1018
1035
except IOError as e :
1019
- raise err .OperationalError (2006 , "MySQL server has gone away (%r)" % (e ,))
1036
+ self ._force_close ()
1037
+ raise err .OperationalError (
1038
+ CR .CR_SERVER_GONE_ERROR ,
1039
+ "MySQL server has gone away (%r)" % (e ,))
1020
1040
1021
1041
def _read_query_result (self , unbuffered = False ):
1022
1042
if unbuffered :
0 commit comments