Bug #106848 mysql.connector throws exception when time field is 0
Submitted: 27 Mar 2022 15:20 Modified: 13 Jul 2022 13:51
Reporter: Gord Shier Email Updates:
Status: Duplicate Impact on me:
None 
Category:Connector / Python Severity:S3 (Non-critical)
Version:8.0.28 OS:Any
Assigned to: CPU Architecture:Any

[27 Mar 2022 15:20] Gord Shier
Description:
When querying a TIME field that is set to 00:00:00, mysql.connector throws an exception when trying to unpack the result.

According to https://dev.mysql.com/doc/internals/en/binary-protocol-value.html:

 to save space the packet can be compressed:

    if year, month, day, hour, minutes, seconds and micro_seconds are all 0, length is 0 and no other field is sent 

How to repeat:
Here is my sample program:

#!venv/bin/python3

import mysql.connector

def q(query):
  cursor = dbh.cursor(prepared=True)
  cursor.execute(query)
  for row in cursor:
    print(f"row = {row}")

dbh = mysql.connector.connect(user="shier", database="test")
q("create temporary table a(b time)")
q("insert into a set b='00:00'")
q("select * from a")

Here is the result:

Traceback (most recent call last):
  File "./b.py", line 14, in <module>
    q("select * from a")
  File "./b.py", line 8, in q
    for row in cursor:
  File "/home/shier/public_html/dxscripts/venv/lib64/python3.6/site-packages/mysql/connector/cursor.py", line 1192, in fetchone
    return self._fetch_row() or None
  File "/home/shier/public_html/dxscripts/venv/lib64/python3.6/site-packages/mysql/connector/cursor.py", line 837, in _fetch_row
    binary=self._binary, columns=self.description)
  File "/home/shier/public_html/dxscripts/venv/lib64/python3.6/site-packages/mysql/connector/connection.py", line 421, in get_row
    (rows, eof) = self.get_rows(count=1, binary=binary, columns=columns)
  File "/home/shier/public_html/dxscripts/venv/lib64/python3.6/site-packages/mysql/connector/connection.py", line 441, in get_rows
    self._socket, columns, count)
  File "/home/shier/public_html/dxscripts/venv/lib64/python3.6/site-packages/mysql/connector/protocol.py", line 476, in read_binary_result
    values = self._parse_binary_values(columns, packet[5:])
  File "/home/shier/public_html/dxscripts/venv/lib64/python3.6/site-packages/mysql/connector/protocol.py", line 448, in _parse_binary_values
    (packet, value) = self._parse_binary_time(packet, field)
  File "/home/shier/public_html/dxscripts/venv/lib64/python3.6/site-packages/mysql/connector/protocol.py", line 413, in _parse_binary_time
    days = struct_unpack('I', data[1:5])[0]

Suggested fix:
Here is a patch that fixes the problem:

diff --git a/mysql/connector/protocol.py b/mysql/connector/protocol.py
index 0ce9cfb..fc465ad 100644
--- a/mysql/connector/protocol.py
+++ b/mysql/connector/protocol.py
@@ -406,6 +406,8 @@ class MySQLProtocol(object):
     def _parse_binary_time(self, packet, field):
         """Parse a time value from a binary packet"""
         length = packet[0]
+        if length == 0:
+            return (packet[1:], datetime.timedelta())
         data = packet[1:length + 1]
         mcs = 0
         if length > 8:
[28 Mar 2022 9:38] MySQL Verification Team
Hello Gord Shier,

Thank you for the report and test case.

regards,
Umesh
[28 Mar 2022 11:00] Gord Shier
Sorry... I cut off the traceback.

The last line says:

struct.error: unpack requires a buffer of 4 bytes
[13 Jul 2022 13:51] Oscar Pacheco
This bug is a duplicate of Bug #91974.