Bug #91974 mysql-connector-python crashes on 0 time value

Submitted: 11 Aug 2018 0:13 Modified: 10 Aug 2022 20:52
Reporter: Robert Walzer Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / Python Severity:S3 (Non-critical)
Version:8.0.12 OS:Any
Assigned to: CPU Architecture:Any

[11 Aug 2018 0:13] Robert Walzer
Description:
The mysql-python-connector binary protocol appears to crash on time value of 0 because it does not deal with payload of size 0 correctly. According to the documentation(https://dev.mysql.com/doc/internals/en/binary-protocol-value.html) time of 00:00.0 can be compressed to size 0 in the packet. The connector yields this crash when reading this value though:

```
Traceback (most recent call last):
  File "script_tests/binary.py", line 14, in <module>
    q("select * from db.t")
  File "script_tests/binary.py", line 7, in q
    for r in c:
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/cursor.py", line 1249, in fetchone
    return self._fetch_row() or None
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/cursor.py", line 851, in _fetch_row
    binary=self._binary, columns=self.description, raw=raw)
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/connection.py", line 465, in get_row
    raw=raw)
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/connection.py", line 491, in get_rows
    self._socket, columns, count, charset)
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/protocol.py", line 478, in read_binary_result
    values = self._parse_binary_values(columns, packet[5:], charset)
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/protocol.py", line 450, in _parse_binary_values
    (packet, value) = self._parse_binary_time(packet, field)
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/protocol.py", line 415, in _parse_binary_time
    days = struct_unpack('I', data[1:5])[0]
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/catch23.py", line 91, in struct_unpack
    return struct.unpack_from(fmt, buffer(buf))
struct.error: unpack_from requires a buffer of at least 4 bytes
```

How to repeat:
```
import mysql.connector
from mysql.connector.cursor import MySQLCursorPrepared

def q(query):
    c = cnx.cursor(cursor_class=MySQLCursorPrepared)
    c.execute(query)
    for r in c:
        print r

cnx = mysql.connector.connect(user='root', database='',port=3306,use_pure=True)
q("create database db")
q("create table db.t(a time)")
q("insert into db.t values(0)")
q("select * from db.t")
```
[12 Aug 2018 8:43] MySQL Verification Team
Hello Robert,

Thank you for the report and test case!

thanks,
Umesh
[13 Aug 2018 16:15] Robert Walzer
I have another test case which causes the connector to crash on a binary column. Would you like me to file a separate bug for this:

  File "script_tests/binary.py", line 14, in <module>
    q("select * from db.t")
  File "script_tests/binary.py", line 7, in q
    for r in c:
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/cursor.py", line 1249, in fetchone
    return self._fetch_row() or None
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/cursor.py", line 851, in _fetch_row
    binary=self._binary, columns=self.description, raw=raw)
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/connection.py", line 465, in get_row
    raw=raw)
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/connection.py", line 491, in get_rows
    self._socket, columns, count, charset)
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/protocol.py", line 478, in read_binary_result
    values = self._parse_binary_values(columns, packet[5:], charset)
  File "/usr/local/lib/python2.7/dist-packages/mysql/connector/protocol.py", line 454, in _parse_binary_values
    values.append(value.decode(charset))
  File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xd0 in position 2: invalid continuation byte

repro:
def q(query):
    c = cnx.cursor(cursor_class=MySQLCursorPrepared)
    c.execute(query)
    for r in c:
        print r

cnx = mysql.connector.connect(user='root', database='',port=3306,use_pure=True)
q("create database db")
q("create table db.t(a binary(16))")
q("insert into db.t values(unhex('D0BFD000000000000000000000000000'))")
q("select * from db.t")
[12 Jul 2022 21:03] Oscar Pacheco
Posted by developer:
 
Patch submitted for review.
[10 Aug 2022 20:52] Philip Olson
Posted by developer:
 
Fixed as of the upcoming MySQL Connector/Python 8.0.31 release, and here's the proposed changelog entry from the documentation team:

The binary protocol would unexpectedly halt when given a time value of 0.
The expected behavior is to receive a 00:00:00 time when given a 0-time
value payload.

Thank you for the bug report.
[8 Sep 2025 22:50] Dillon Sadofsky
This still seems to happen in Connector/Python 9.4.  I'm guessing it was fixed specifically in the Prepared cursor, but I get it when using the base MySQLCursor.  I also seem to be getting it when I select just a mysql DATE column (no time element).  I'm guessing its the same issue since there is no time, implicitly 0.  But IDK, maybe its a new version of the same bug.
[8 Sep 2025 22:55] Dillon Sadofsky
For anyone else who stumbles on this bug, I was able to work around it by forcing the DATE column to be a string.  Since the connector automatically converts all column types, I had to change its type in the query with a CAST:
SELECT CAST(`effectivedate` AS CHAR) AS `effectivedate` FROM ....

Then I no longer got the 4 BYTE error.

So seems to be a bug specifically in the date/datetime conversion code in the newer versions.

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.057 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.