Skip to content

Commit a825b84

Browse files
authored
Don't use PyTuple_Resize (#436)
1 parent 0887495 commit a825b84

File tree

2 files changed

+33
-50
lines changed

2 files changed

+33
-50
lines changed

.travis.yml

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ language: python
55
python:
66
- "nightly"
77
- "pypy3"
8+
- "3.9-dev"
89
- "3.8"
910
- "3.7"
1011
- "3.6"
@@ -42,7 +43,7 @@ jobs:
4243
name: "Django 2.2 test"
4344
env:
4445
- DJANGO_VERSION=2.2.7
45-
python: "3.5"
46+
python: "3.8"
4647
install:
4748
- pip install -U pip
4849
- wget https://github.com/django/django/archive/${DJANGO_VERSION}.tar.gz
@@ -58,7 +59,7 @@ jobs:
5859

5960
script:
6061
- cd django-${DJANGO_VERSION}/tests/
61-
- ./runtests.py --parallel=1 --settings=test_mysql
62+
- ./runtests.py --parallel=2 --settings=test_mysql
6263
- name: flake8
6364
python: "3.8"
6465
install:

MySQLdb/_mysql.c

+30-48
Original file line numberDiff line numberDiff line change
@@ -1298,19 +1298,16 @@ _mysql_row_to_dict_old(
12981298

12991299
typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW);
13001300

1301-
int
1301+
Py_ssize_t
13021302
_mysql__fetch_row(
13031303
_mysql_ResultObject *self,
1304-
PyObject **r,
1305-
int skiprows,
1306-
int maxrows,
1304+
PyObject *r, /* list object */
1305+
Py_ssize_t maxrows,
13071306
_PYFUNC *convert_row)
13081307
{
1309-
int i;
1310-
MYSQL_ROW row;
1311-
1312-
for (i = skiprows; i<(skiprows+maxrows); i++) {
1313-
PyObject *v;
1308+
Py_ssize_t i;
1309+
for (i = 0; i < maxrows; i++) {
1310+
MYSQL_ROW row;
13141311
if (!self->use)
13151312
row = mysql_fetch_row(self->result);
13161313
else {
@@ -1320,19 +1317,20 @@ _mysql__fetch_row(
13201317
}
13211318
if (!row && mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) {
13221319
_mysql_Exception((_mysql_ConnectionObject *)self->conn);
1323-
goto error;
1320+
return -1;
13241321
}
13251322
if (!row) {
1326-
if (_PyTuple_Resize(r, i) == -1) goto error;
13271323
break;
13281324
}
1329-
v = convert_row(self, row);
1330-
if (!v) goto error;
1331-
PyTuple_SET_ITEM(*r, i, v);
1325+
PyObject *v = convert_row(self, row);
1326+
if (!v) return -1;
1327+
if (PyList_Append(r, v)) {
1328+
Py_DECREF(v);
1329+
return -1;
1330+
}
1331+
Py_DECREF(v);
13321332
}
1333-
return i-skiprows;
1334-
error:
1335-
return -1;
1333+
return i;
13361334
}
13371335

13381336
static char _mysql_ResultObject_fetch_row__doc__[] =
@@ -1359,7 +1357,7 @@ _mysql_ResultObject_fetch_row(
13591357
_mysql_row_to_dict_old
13601358
};
13611359
_PYFUNC *convert_row;
1362-
int maxrows=1, how=0, skiprows=0, rowsadded;
1360+
int maxrows=1, how=0;
13631361
PyObject *r=NULL;
13641362

13651363
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:fetch_row", kwlist,
@@ -1371,40 +1369,24 @@ _mysql_ResultObject_fetch_row(
13711369
return NULL;
13721370
}
13731371
convert_row = row_converters[how];
1374-
if (maxrows) {
1375-
if (!(r = PyTuple_New(maxrows))) goto error;
1376-
1377-
// see: https://docs.python.org/3/library/gc.html#gc.get_referrers
1378-
// This function can get a reference to the tuple r, and if that
1379-
// code is preempted while holding a ref to r, the _PyTuple_Resize
1380-
// will raise a SystemError because the ref count is 2.
1381-
PyObject_GC_UnTrack(r);
1382-
rowsadded = _mysql__fetch_row(self, &r, skiprows, maxrows, convert_row);
1383-
if (rowsadded == -1) goto error;
1384-
PyObject_GC_Track(r);
1385-
} else {
1372+
if (!maxrows) {
13861373
if (self->use) {
1387-
maxrows = 1000;
1388-
if (!(r = PyTuple_New(maxrows))) goto error;
1389-
while (1) {
1390-
rowsadded = _mysql__fetch_row(self, &r, skiprows,
1391-
maxrows, convert_row);
1392-
if (rowsadded == -1) goto error;
1393-
skiprows += rowsadded;
1394-
if (rowsadded < maxrows) break;
1395-
if (_PyTuple_Resize(&r, skiprows+maxrows) == -1)
1396-
goto error;
1397-
}
1374+
maxrows = INT_MAX;
13981375
} else {
1399-
/* XXX if overflow, maxrows<0? */
1400-
maxrows = (int) mysql_num_rows(self->result);
1401-
if (!(r = PyTuple_New(maxrows))) goto error;
1402-
rowsadded = _mysql__fetch_row(self, &r, 0,
1403-
maxrows, convert_row);
1404-
if (rowsadded == -1) goto error;
1376+
// todo: preallocate.
1377+
maxrows = (Py_ssize_t) mysql_num_rows(self->result);
14051378
}
14061379
}
1407-
return r;
1380+
if (!(r = PyList_New(0))) goto error;
1381+
Py_ssize_t rowsadded = _mysql__fetch_row(self, r, maxrows, convert_row);
1382+
if (rowsadded == -1) goto error;
1383+
1384+
/* DB-API allows return rows as list.
1385+
* But we need to return list because Django expecting tuple.
1386+
*/
1387+
PyObject *t = PyList_AsTuple(r);
1388+
Py_DECREF(r);
1389+
return t;
14081390
error:
14091391
Py_XDECREF(r);
14101392
return NULL;

0 commit comments

Comments
 (0)