| Bug #74483 | recv_plain bug | ||
|---|---|---|---|
| Submitted: | 21 Oct 2014 13:20 | Modified: | 3 Dec 2014 15:23 |
| Reporter: | Daniil Terentev | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | Connector / Python | Severity: | S1 (Critical) |
| Version: | 2.0.2 | OS: | Windows (Windows 7) |
| Assigned to: | Peeyush Gupta | CPU Architecture: | Any |
[21 Oct 2014 14:07]
MySQL Verification Team
Thank you for the report.
I couldn't repeat this issue on Linux test box.
Could you please share schema/data which helps to trigger? May be windows specific?
[root@cluster-repo mysql-advanced-5.6.22]# rpm -qa|grep mysql-connector
mysql-connector-python-commercial-2.0.1-1.el6.noarch
[root@cluster-repo mysql-advanced-5.6.22]#
[root@cluster-repo mysql-advanced-5.6.22]# python
Python 2.6.6 (r266:84292, Jan 22 2014, 01:49:05)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import mysql.connector
>>> Daatabase = mysql.connector.connect(host='localhost', user='root', passwd='', db='test')
>>> DaatabaseCursor = Daatabase.cursor()
>>> DaatabaseCursor.execute("SELECT id,id1,id2 from t1")
>>> Reesult = DaatabaseCursor.fetchall()
>>> DaatabaseCursor.close()
True
>>> Daatabase.close()
>>>
[21 Oct 2014 14:14]
Daniil Terentev
Table i'v posted trigged this bug for me. Python 3.4.2 (v3.4.2:ab2c023a9432, Oct 6 2014, 22:16:31) [MSC v.1600 64 bit (AMD64)] on win32 I think cause of this bug somwhere in windows network drivers. May be Python tries to use it in some unproper way. But i'm not shure.
[21 Oct 2014 14:17]
Daniil Terentev
Forgot to mention that database launched on ubuntu server 14.04 and python launched on windows 7 laptop.
[31 Oct 2014 10:15]
Geert Vanderkelen
It is hard to verify, but there is definitely a flaw in receiving the first 4 bytes. We had replaced this code with recv_into(), but it is probably best to revert and use while-loop (like in the code Python 2.6).
[12 Nov 2014 10:19]
Daniil Terentev
Problem is still unsolved. in 2.0.2 got the same error message
[3 Dec 2014 15:23]
Paul DuBois
Noted in 2.0.3 changelog. recv_plain() could fail to read a packet header correctly, resulting in a lost connection.
[31 Jan 2015 17:05]
HU Cao
Looks like this bug is closed. I have met the same issue and I am waiting the 2.0.3 and installed immediately.This version indeed fixes the problem . However, it starts to hung occurationly. I think some other fix in 2.0.3 does not work with this fix. I move back the Daniil's fix with 2.0.2. Please investigate the reason why the connection hungs. Thanks, Hu
[5 Feb 2015 12:29]
Peeyush Gupta
Seems like the patch for this bug couldn't fix it properly, sorry for the inconvenience, we'll fix the issue as soon as possible.
[6 Feb 2015 0:04]
Ivan Kharybin
I've been running into same problem for hours already, so issue cannot be considered "closed". Here is what helped me. network.py line has following lines [224,225]: while len(packet) < 4: chunk = self.sock.recv(4) I'm not very familiar with python sockets, but as far as I can tell socked used here is blocking. What it means is when you call a recv(4) function, it won't return unless at least 4 bytes are received. And if MySQL header gets chunked at some point, this loop becomes an infinite one, since packet length is less than 4 (chunked 4-bytes header, remember?) and recv(4) will never return since we already got some header bytes and cannot receive another 4. So I simply changed these two lines to the following: while len(packet) < 4: chunk = self.sock.recv(4 - len(packet)) So far everything has been working without issues, and my script is currently processing its 6th million row of MySQL data.
[10 Feb 2015 9:43]
Viktor Liljeblad
Still having this issue with version 2.0.3.
Applying the fix suggested by Ivan Kharybin helped, but was not enough for me.
I also had to apply a similar fix to network.py lines [261,262]:
while len(header) < 4:
chunk = self.sock.recv(4)
Changed to:
while len(header) < 4:
chunk = self.sock.recv(4 - len(header))
This seems to have helped the problem for me.
[22 Apr 2015 19:09]
Eric Wong
I can also confirm that the fix suggested by Ivan Kharybin is working for me.
[20 Dec 2016 22:13]
Bender Rodriguez
I have made the updates suggested by Viktor Liljeblad and Ivan Kharybin, but I am still having this issue...
File "/Library/Python/2.7/site-packages/mysql/connector/cursor.py", line 1207, in fetchone
row = self._fetch_row()
File "/Library/Python/2.7/site-packages/mysql/connector/cursor.py", line 807, in _fetch_row
binary=self._binary, columns=self.description)
File "/Library/Python/2.7/site-packages/mysql/connector/connection.py", line 421, in get_row
(rows, eof) = self.get_rows(count=1, binary=binary, columns=columns)
File "/Library/Python/2.7/site-packages/mysql/connector/connection.py", line 443, in get_rows
rows = self._protocol.read_text_result(self._socket, count)
File "/Library/Python/2.7/site-packages/mysql/connector/protocol.py", line 322, in read_text_result
packet = sock.recv()
File "/Library/Python/2.7/site-packages/mysql/connector/network.py", line 250, in recv_plain
read = self.sock.recv_into(packet_view, rest)

Description: This Python code import mysql.connector Daatabase = mysql.connector.connect(host='192.168.0.5', user='pupkin', passwd='vasya', db='daatabase') DaatabaseCursor = Daatabase.cursor() DaatabaseCursor.execute("SELECT fiield, fieeld, fielld FROM taable") Reesult = DaatabaseCursor.fetchall() DaatabaseCursor.close() Daatabase.close() Causes this error Traceback (most recent call last): File "\free\polygon.py", line 6, in <module> Reesult = DaatabaseCursor.fetchall() File "C:\Python34\lib\site-packages\mysql\connector\cursor.py", line 823, in fetchall (rows, eof) = self._connection.get_rows() File "C:\Python34\lib\site-packages\mysql\connector\connection.py", line 669, in get_rows rows = self._protocol.read_text_result(self._socket, count) File "C:\Python34\lib\site-packages\mysql\connector\protocol.py", line 309, in read_text_result packet = sock.recv() File "C:\Python34\lib\site-packages\mysql\connector\network.py", line 226, in recv_plain raise errors.InterfaceError(errno=2013) mysql.connector.errors.InterfaceError: 2013: Lost connection to MySQL server during query shell returned 1 It hapens in 90% of script runs. I don't know what it depends on. Same bug mentioned here http://stackoverflow.com/questions/26382868/python-mysql-connector-lost-connection-errno-2... How to repeat: Repeat what? Suggested fix: I'v replaced this part of code in network.py """Receive packets from the MySQL server""" try: # Read the header of the MySQL packet, 4 bytes packet = bytearray(4) read = self.sock.recv_into(packet, 4) if read != 4: raise errors.InterfaceError(errno=2013) # Save the packet number and payload length self._packet_number = packet[3] if PY2: payload_len = struct.unpack_from( "<I", buffer(packet[0:3] + b'\x00'))[0] # pylint: disable=E0602 else: payload_len = struct.unpack("<I", packet[0:3] + b'\x00')[0] # Read the payload rest = payload_len packet.extend(bytearray(payload_len)) packet_view = memoryview(packet) # pylint: disable=E0602 packet_view = packet_view[4:] while rest: read = self.sock.recv_into(packet_view, rest) if read == 0 and rest > 0: raise errors.InterfaceError(errno=2013) packet_view = packet_view[read:] rest -= read return packet except IOError as err: raise errors.OperationalError( errno=2055, values=(self.get_address(), _strioerror(err))) With this code taken from network.py of Connector version 1.2.3 """Receive packets from the MySQL server""" packet = b'' try: # Read the header of the MySQL packet, 4 bytes packet = self.sock.recv(1) while len(packet) < 4: chunk = self.sock.recv(1) if not chunk: raise errors.InterfaceError(errno=2013) packet += chunk # Save the packet number and total packet length from header self._packet_number = packet[3] packet_totlen = struct.unpack("<I", packet[0:3] + b'\x00')[0] + 4 # Read the rest of the packet rest = packet_totlen - len(packet) while rest > 0: chunk = self.sock.recv(rest) if not chunk: raise errors.InterfaceError(errno=2013) packet += chunk rest = packet_totlen - len(packet) return packet except IOError as err: raise errors.OperationalError( errno=2055, values=(self.get_address(), _strioerror(err))) and it works fine.