Skip to content

Commit a7e6d14

Browse files
authored
Raise SERVER_LOST error for MariaDB's shutdown packet (PyMySQL#540)
Raise SERVER_LOST error for MariaDB's shutdown packet fixes PyMySQL#526
1 parent 7742180 commit a7e6d14

File tree

1 file changed

+28
-8
lines changed

1 file changed

+28
-8
lines changed

pymysql/connections.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import warnings
1818

1919
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
2121
from .converters import escape_item, escape_string, through, conversions as _conv
2222
from .cursors import Cursor
2323
from .optionfile import Parser
@@ -524,6 +524,7 @@ class Connection(object):
524524

525525
_sock = None
526526
_auth_plugin_name = ''
527+
_closed = False
527528

528529
def __init__(self, host=None, user=None, password="",
529530
database=None, port=0, unix_socket=None,
@@ -715,8 +716,11 @@ def _create_ssl_ctx(self, sslp):
715716

716717
def close(self):
717718
"""Send the quit message and close the socket"""
718-
if self._sock is None:
719+
if self._closed:
719720
raise err.Error("Already closed")
721+
self._closed = True
722+
if self._sock is None:
723+
return
720724
send_data = struct.pack('<iB', 1, COMMAND.COM_QUIT)
721725
try:
722726
self._write_bytes(send_data)
@@ -732,7 +736,8 @@ def close(self):
732736
def open(self):
733737
return self._sock is not None
734738

735-
def __del__(self):
739+
def _force_close(self):
740+
"""Close connection without QUIT message"""
736741
if self._sock:
737742
try:
738743
self._sock.close()
@@ -741,6 +746,8 @@ def __del__(self):
741746
self._sock = None
742747
self._rfile = None
743748

749+
__del__ = _force_close
750+
744751
def autocommit(self, value):
745752
self.autocommit_mode = bool(value)
746753
current = self.get_autocommit()
@@ -884,6 +891,7 @@ def set_charset(self, charset):
884891
self.encoding = encoding
885892

886893
def connect(self, sock=None):
894+
self._closed = False
887895
try:
888896
if sock is None:
889897
if self.unix_socket and self.host in ('localhost', '127.0.0.1'):
@@ -977,8 +985,15 @@ def _read_packet(self, packet_type=MysqlPacket):
977985
btrl, btrh, packet_number = struct.unpack('<HBB', packet_header)
978986
bytes_to_read = btrl + (btrh << 16)
979987
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))
982997
self._next_seq_id = (self._next_seq_id + 1) % 256
983998

984999
recv_data = self._read_bytes(bytes_to_read)
@@ -1003,20 +1018,25 @@ def _read_bytes(self, num_bytes):
10031018
except (IOError, OSError) as e:
10041019
if e.errno == errno.EINTR:
10051020
continue
1021+
self._force_close()
10061022
raise err.OperationalError(
1007-
2013,
1023+
CR.CR_SERVER_LOST,
10081024
"Lost connection to MySQL server during query (%s)" % (e,))
10091025
if len(data) < num_bytes:
1026+
self._force_close()
10101027
raise err.OperationalError(
1011-
2013, "Lost connection to MySQL server during query")
1028+
CR.CR_SERVER_LOST, "Lost connection to MySQL server during query")
10121029
return data
10131030

10141031
def _write_bytes(self, data):
10151032
self._sock.settimeout(self._write_timeout)
10161033
try:
10171034
self._sock.sendall(data)
10181035
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,))
10201040

10211041
def _read_query_result(self, unbuffered=False):
10221042
if unbuffered:

0 commit comments

Comments
 (0)