python - MySQL 连接器/python (v1.1.6) 在查询许多列并使用预准备语句时失败

标签 python mysql

我收到错误:调用 cursor.fetchone()cursor.fetchall() 时,unpack 需要长度为 8 的字符串参数或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 连接器/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。

最佳答案

我怀疑这是 mysql 连接器/python 中的一个真正的错误。该错误位于 protocol.py: MySQLProtocol._parse_binary_values()utils.py: intread() 中。

utils.py: intread() 中的代码期望一个不超过 8 个字节的字符串,但 protocol.py: MySQLProtocol._parse_binary_values() 传入一个当列数超过 62 (8 * 8 - 2) 时,会出现更长的字符串。

下面是相关代码片段:

在协议(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

关于python - MySQL 连接器/python (v1.1.6) 在查询许多列并使用预准备语句时失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23506478/

相关文章:

Python - GroupBy 对象的滚动函数

python - 用etree解析xml

python - 使用 Python 转换为 CSV 的文本文件与使用 Excel 转换不同

java - 插入 blob 作为数据类型时出现数据截断错误

mysql - 将 case 语句添加到 SQL 查询

mysql - 带有连接的sql删除导致语法错误

python - 如何禁用 Selenium (Python 3) 上的 geckodriver 日志?

python - 为什么我不能在 IPython 笔记本中导入 OpenCV (cv2)?

mysql - SQL ORDER BY - 按两列之间的值选择顺序

MySQL:具有几乎相似字段的表的外键