Don't use PyTuple_Resize (#436)

This commit is contained in:
Inada Naoki
2020-07-03 11:20:38 +09:00
committed by GitHub
parent 0887495b53
commit a825b849ff
2 changed files with 33 additions and 50 deletions

View File

@ -5,6 +5,7 @@ language: python
python: python:
- "nightly" - "nightly"
- "pypy3" - "pypy3"
- "3.9-dev"
- "3.8" - "3.8"
- "3.7" - "3.7"
- "3.6" - "3.6"
@ -42,7 +43,7 @@ jobs:
name: "Django 2.2 test" name: "Django 2.2 test"
env: env:
- DJANGO_VERSION=2.2.7 - DJANGO_VERSION=2.2.7
python: "3.5" python: "3.8"
install: install:
- pip install -U pip - pip install -U pip
- wget https://github.com/django/django/archive/${DJANGO_VERSION}.tar.gz - wget https://github.com/django/django/archive/${DJANGO_VERSION}.tar.gz
@ -58,7 +59,7 @@ jobs:
script: script:
- cd django-${DJANGO_VERSION}/tests/ - cd django-${DJANGO_VERSION}/tests/
- ./runtests.py --parallel=1 --settings=test_mysql - ./runtests.py --parallel=2 --settings=test_mysql
- name: flake8 - name: flake8
python: "3.8" python: "3.8"
install: install:

View File

@ -1298,19 +1298,16 @@ _mysql_row_to_dict_old(
typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW); typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW);
int Py_ssize_t
_mysql__fetch_row( _mysql__fetch_row(
_mysql_ResultObject *self, _mysql_ResultObject *self,
PyObject **r, PyObject *r, /* list object */
int skiprows, Py_ssize_t maxrows,
int maxrows,
_PYFUNC *convert_row) _PYFUNC *convert_row)
{ {
int i; Py_ssize_t i;
MYSQL_ROW row; for (i = 0; i < maxrows; i++) {
MYSQL_ROW row;
for (i = skiprows; i<(skiprows+maxrows); i++) {
PyObject *v;
if (!self->use) if (!self->use)
row = mysql_fetch_row(self->result); row = mysql_fetch_row(self->result);
else { else {
@ -1320,19 +1317,20 @@ _mysql__fetch_row(
} }
if (!row && mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) { if (!row && mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) {
_mysql_Exception((_mysql_ConnectionObject *)self->conn); _mysql_Exception((_mysql_ConnectionObject *)self->conn);
goto error; return -1;
} }
if (!row) { if (!row) {
if (_PyTuple_Resize(r, i) == -1) goto error;
break; break;
} }
v = convert_row(self, row); PyObject *v = convert_row(self, row);
if (!v) goto error; if (!v) return -1;
PyTuple_SET_ITEM(*r, i, v); if (PyList_Append(r, v)) {
Py_DECREF(v);
return -1;
}
Py_DECREF(v);
} }
return i-skiprows; return i;
error:
return -1;
} }
static char _mysql_ResultObject_fetch_row__doc__[] = static char _mysql_ResultObject_fetch_row__doc__[] =
@ -1359,7 +1357,7 @@ _mysql_ResultObject_fetch_row(
_mysql_row_to_dict_old _mysql_row_to_dict_old
}; };
_PYFUNC *convert_row; _PYFUNC *convert_row;
int maxrows=1, how=0, skiprows=0, rowsadded; int maxrows=1, how=0;
PyObject *r=NULL; PyObject *r=NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:fetch_row", kwlist, if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:fetch_row", kwlist,
@ -1371,40 +1369,24 @@ _mysql_ResultObject_fetch_row(
return NULL; return NULL;
} }
convert_row = row_converters[how]; convert_row = row_converters[how];
if (maxrows) { if (!maxrows) {
if (!(r = PyTuple_New(maxrows))) goto error;
// see: https://docs.python.org/3/library/gc.html#gc.get_referrers
// This function can get a reference to the tuple r, and if that
// code is preempted while holding a ref to r, the _PyTuple_Resize
// will raise a SystemError because the ref count is 2.
PyObject_GC_UnTrack(r);
rowsadded = _mysql__fetch_row(self, &r, skiprows, maxrows, convert_row);
if (rowsadded == -1) goto error;
PyObject_GC_Track(r);
} else {
if (self->use) { if (self->use) {
maxrows = 1000; maxrows = INT_MAX;
if (!(r = PyTuple_New(maxrows))) goto error;
while (1) {
rowsadded = _mysql__fetch_row(self, &r, skiprows,
maxrows, convert_row);
if (rowsadded == -1) goto error;
skiprows += rowsadded;
if (rowsadded < maxrows) break;
if (_PyTuple_Resize(&r, skiprows+maxrows) == -1)
goto error;
}
} else { } else {
/* XXX if overflow, maxrows<0? */ // todo: preallocate.
maxrows = (int) mysql_num_rows(self->result); maxrows = (Py_ssize_t) mysql_num_rows(self->result);
if (!(r = PyTuple_New(maxrows))) goto error;
rowsadded = _mysql__fetch_row(self, &r, 0,
maxrows, convert_row);
if (rowsadded == -1) goto error;
} }
} }
return r; if (!(r = PyList_New(0))) goto error;
Py_ssize_t rowsadded = _mysql__fetch_row(self, r, maxrows, convert_row);
if (rowsadded == -1) goto error;
/* DB-API allows return rows as list.
* But we need to return list because Django expecting tuple.
*/
PyObject *t = PyList_AsTuple(r);
Py_DECREF(r);
return t;
error: error:
Py_XDECREF(r); Py_XDECREF(r);
return NULL; return NULL;