Skip to content

Commit 4e42684

Browse files
committed
BUG20834643: Attribute Error while promoting servers using MySQL Fabric
An AttributeError was occuring while using Connector/Python with MySQL Fabric, the reason being named tuple cursor returning wrong results with fetchall() method. We fix this by correctly tranforming rows to named tuples when fetched with MySQLCursor.fetchall() method. This patch also fixes BUG#20836026. A test case has been added for BUG#20834643.
1 parent e6f584e commit 4e42684

File tree

2 files changed

+79
-6
lines changed

2 files changed

+79
-6
lines changed

lib/mysql/connector/cursor.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# MySQL Connector/Python - MySQL driver written in Python.
2-
# Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
33

44
# MySQL Connector/Python is licensed under the terms of the GPLv2
55
# <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -1215,7 +1215,7 @@ def _row_to_python(self, rowdata, desc=None):
12151215
if hasattr(self._connection, 'converter'):
12161216
row = self._connection.converter.row_to_python(rowdata, desc)
12171217
else:
1218-
rowdata = row
1218+
row = rowdata
12191219

12201220
if row:
12211221
# pylint: disable=W0201
@@ -1243,16 +1243,15 @@ def fetchall(self):
12431243
if self._nextrow[0]:
12441244
rows.insert(0, self._nextrow[0])
12451245

1246-
if hasattr(self._connection, 'converter'):
1247-
row_to_python = self._connection.converter.row_to_python
1248-
rows = [row_to_python(row, self.description) for row in rows]
1246+
res = [self._row_to_python(row, self.description)
1247+
for row in rows]
12491248

12501249
self._handle_eof(eof)
12511250
rowcount = len(rows)
12521251
if rowcount >= 0 and self._rowcount == -1:
12531252
self._rowcount = 0
12541253
self._rowcount += rowcount
1255-
return rows
1254+
return res
12561255

12571256

12581257
class MySQLCursorBufferedDict(MySQLCursorDict, MySQLCursorBuffered):

tests/test_bugs.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3504,3 +3504,77 @@ def test_set(self):
35043504
for row in cur:
35053505
self.assertEqual(row, dict(zip(('id', 'name', 'dept'), data[i])))
35063506
i += 1
3507+
3508+
3509+
class BugOra20834643(tests.MySQLConnectorTests):
3510+
"""BUG#20834643: ATTRIBUTE ERROR NOTICED WHILE TRYING TO PROMOTE SERVERS
3511+
"""
3512+
def setUp(self):
3513+
config = tests.get_mysql_config()
3514+
cnx = connection.MySQLConnection(**config)
3515+
cur = cnx.cursor()
3516+
3517+
self.tbl = 'Bug20834643'
3518+
cur.execute("DROP TABLE IF EXISTS {0}".format(self.tbl))
3519+
3520+
create = ("CREATE TABLE {0} (id INT, name VARCHAR(5), dept VARCHAR(5)) "
3521+
"DEFAULT CHARSET latin1".format(self.tbl))
3522+
cur.execute(create)
3523+
cur.close()
3524+
cnx.close()
3525+
3526+
def tearDown(self):
3527+
config = tests.get_mysql_config()
3528+
cnx = connection.MySQLConnection(**config)
3529+
cur = cnx.cursor()
3530+
cur.execute("DROP TABLE IF EXISTS {0}".format(self.tbl))
3531+
cur.close()
3532+
cnx.close()
3533+
3534+
@foreach_cnx()
3535+
def test_set(self):
3536+
cur = self.cnx.cursor()
3537+
sql = "INSERT INTO {0} VALUES(%s, %s, %s)".format(self.tbl)
3538+
3539+
data = [
3540+
(1, 'abc', 'cs'),
3541+
(2, 'def', 'is'),
3542+
(3, 'ghi', 'cs'),
3543+
(4, 'jkl', 'it'),
3544+
]
3545+
cur.executemany(sql, data)
3546+
cur.close()
3547+
3548+
cur = self.cnx.cursor(named_tuple=True)
3549+
cur.execute("SELECT * FROM {0}".format(self.tbl))
3550+
3551+
res = cur.fetchone()
3552+
self.assertEqual(data[0], (res.id, res.name, res.dept))
3553+
res = cur.fetchall()
3554+
exp = []
3555+
for row in res:
3556+
exp.append((row.id, row.name, row.dept))
3557+
self.assertEqual(exp, data[1:])
3558+
cur.close()
3559+
3560+
cur = self.cnx.cursor(named_tuple=True, buffered=True)
3561+
cur.execute("SELECT * FROM {0}".format(self.tbl))
3562+
res = cur.fetchone()
3563+
self.assertEqual(data[0], (res.id, res.name, res.dept))
3564+
res = cur.fetchall()
3565+
exp = []
3566+
for row in res:
3567+
exp.append((row.id, row.name, row.dept))
3568+
self.assertEqual(exp, data[1:])
3569+
cur.close()
3570+
3571+
cur = self.cnx.cursor(named_tuple=True, buffered=False)
3572+
cur.execute("SELECT * FROM {0}".format(self.tbl))
3573+
res = cur.fetchone()
3574+
self.assertEqual(data[0], (res.id, res.name, res.dept))
3575+
res = cur.fetchall()
3576+
exp = []
3577+
for row in res:
3578+
exp.append((row.id, row.name, row.dept))
3579+
self.assertEqual(exp, data[1:])
3580+
cur.close()

0 commit comments

Comments
 (0)