我在调用unpack requires a string argument of length 8
或cursor.fetchone()
或cursor.fetchall()
时收到错误:cursor.fetchmany()
。下面是重现问题的调用顺序。
In [3]: cursor = connector.cursor(prepared=True)
In [4]: stmt = "SELECT * FROM my_table WHERE my_key=%s"
In [5]: cursor.execute(stmt, ('my_value',))
In [6]: cursor.fetchone()
---------------------------------------------------------------------------
error Traceback (most recent call last)
<ipython-input-6-5501e92f1036> in <module>()
----> 1 cursor.fetchone()
/usr/lib/python2.7/dist-packages/mysql/connector/cursor.pyc in fetchone(self)
1041 Returns a tuple or None.
1042 """
-> 1043 return self._fetch_row() or None
1044
1045 def fetchmany(self, size=None):
/usr/lib/python2.7/dist-packages/mysql/connector/cursor.pyc in _fetch_row(self)
709 if self._nextrow == (None, None):
710 (row, eof) = self._connection.get_row(
--> 711 binary=self._binary, columns=self.description)
712 else:
713 (row, eof) = self._nextrow
/usr/lib/python2.7/dist-packages/mysql/connector/connection.pyc in get_row(self, binary, columns)
599 Returns a tuple.
600 """
--> 601 (rows, eof) = self.get_rows(count=1, binary=binary, columns=columns)
602 if len(rows):
603 return (rows[0], eof)
/usr/lib/python2.7/dist-packages/mysql/connector/connection.pyc in get_rows(self, count, binary, columns)
580 if binary:
581 rows = self._protocol.read_binary_result(
--> 582 self._socket, columns, count)
583 else:
584 rows = self._protocol.read_text_result(self._socket, count)
/usr/lib/python2.7/dist-packages/mysql/connector/protocol.pyc in read_binary_result(self, sock, columns, count)
398 elif packet[4] == '\x00':
399 eof = None
--> 400 values = self._parse_binary_values(columns, packet[5:])
401 if eof is None and values is not None:
402 rows.append(values)
/usr/lib/python2.7/dist-packages/mysql/connector/protocol.pyc in _parse_binary_values(self, fields, packet)
349 """Parse values from a binary result packet"""
350 null_bitmap_length = (len(fields) + 7 + 2) // 8
--> 351 null_bitmap = utils.intread(packet[0:null_bitmap_length])
352 packet = packet[null_bitmap_length:]
353
/usr/lib/python2.7/dist-packages/mysql/connector/utils.pyc in intread(buf)
43 else:
44 tmp = buf + '\x00'*(8-length)
---> 45 return struct.unpack('<Q', tmp)[0]
46 except:
47 raise
my_table
有81列。
如果我只选择几列,即将stmt
更改为SELECT my_col1,my_col2,my_col3 from my_table WHERE my_key=%s
,则此问题不会重现。
我怀疑这是mysql connector / python中的一个错误。
我做错了吗?
我的mysql连接器/ python版本是1.1.6
,我是从http://dev.mysql.com/get/Downloads/Connector-Python/mysql-connector-python_1.1.6-1ubuntu12.04_all.deb下载的。我的操作系统是ubuntu 13.04。
答案 0 :(得分:0)
我怀疑这是mysql connector / python中的一个真正的错误。该错误位于protocol.py: MySQLProtocol._parse_binary_values()
或utils.py: intread()
。
utils.py: intread()
中的代码需要一个不超过8个字节的字符串,但当列数超过62(8 * 8 - 2)时,protocol.py: MySQLProtocol._parse_binary_values()
会传入更长的字符串。
以下是相关的代码段:
在protocol.py中:
348: def _parse_binary_values(self, fields, packet):
349: """Parse values from a binary result packet"""
350: null_bitmap_length = (len(fields) + 7 + 2) // 8
351: null_bitmap = utils.intread(packet[0:null_bitmap_length])
352:
353: values = []
354: for pos, field in enumerate(fields):
355: if null_bitmap & 1 << (pos + 2):
在utils.py中:
32: def intread(buf):
33: """Unpacks the given buffer to an integer"""
34: try:
35: if isinstance(buf, int):
36: return buf
37: length = len(buf)
38: if length == 1:
39: return int(ord(buf))
40: if length <= 4:
41: tmp = buf + '\x00'*(4-length)
42: return struct.unpack('<I', tmp)[0]
43: else:
44: tmp = buf + '\x00'*(8-length)
45: return struct.unpack('<Q', tmp)[0]
46: except:
47: raise
我可以通过进行以下更改来解决我的问题:
在protocol.py中:
348: def _parse_binary_values(self, fields, packet):
349: """Parse values from a binary result packet"""
350: null_bitmap_length = (len(fields) + 7 + 2) // 8
351: null_bitmap = utils.read_bitmap(packet[0:null_bitmap_length])
352:
353: values = []
354: for pos, field in enumerate(fields):
355: if null_bitmap.test_bit(pos + 2):
在utils.py中(添加以下行):
class MySqlIntBitmap(object):
def __init__(self, value):
self.int_bitmap = value
def test_bit(self, bit):
return (self.int_bitmap & (1 << bit))
class MySqlByteArrayBitmap(object):
def __init__(self, value):
self.byte_array_bitmap = value
def test_bit(self, bit):
index = bit // 8
entry_bit = bit % 8
return (self.byte_array_bitmap[index] & (1 << entry_bit))
def read_bitmap(buf):
"""Unpacks the given buffer to a bitmap"""
try:
if isinstance(buf, int):
return MySqlIntBitmap(buf)
length = len(buf)
if length == 1:
return MySqlIntBitmap(int(ord(buf)))
if length <= 4:
tmp = buf + '\x00'*(4-length)
return MySqlIntBitmap(struct.unpack('<I', tmp)[0])
elif length <= 8:
tmp = buf + '\x00'*(8-length)
return MySqlIntBitmap(struct.unpack('<Q', tmp)[0])
else:
return MySqlByteArrayBitmap([int(ord(i)) for i in buf])
except:
raise