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:
None 
Category:Connector / Python Severity:S1 (Critical)
Version:2.0.2 OS:Windows (Windows 7)
Assigned to: Peeyush Gupta CPU Architecture:Any

[21 Oct 2014 13:20] Daniil Terentev
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.
[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)