mirror of
https://github.com/PyMySQL/mysqlclient.git
synced 2025-08-15 19:31:54 +08:00
Fix memory leak (maybe).
This commit is contained in:
@ -139,6 +139,13 @@ def escape_dict(d, qc):
|
|||||||
d2[k] = qc.get(type(v), String2Literal)(v)
|
d2[k] = qc.get(type(v), String2Literal)(v)
|
||||||
return d2
|
return d2
|
||||||
|
|
||||||
|
def _fetchall(result, *args):
|
||||||
|
rows = r = list(apply(result.fetch_row, args))
|
||||||
|
while 1:
|
||||||
|
rows = list(apply(result.fetch_row, args))
|
||||||
|
if not rows: break
|
||||||
|
r.extend(list(rows))
|
||||||
|
return r
|
||||||
|
|
||||||
class BaseCursor:
|
class BaseCursor:
|
||||||
|
|
||||||
@ -208,10 +215,10 @@ class BaseCursor:
|
|||||||
qc = self.connection.quote_conv
|
qc = self.connection.quote_conv
|
||||||
try:
|
try:
|
||||||
q = [query % escape(args[0], qc)]
|
q = [query % escape(args[0], qc)]
|
||||||
except TypeError, m:
|
except TypeError, msg:
|
||||||
if m.args[0] in ("not enough arguments for format string",
|
if msg.args[0] in ("not enough arguments for format string",
|
||||||
"not all arguments converted"):
|
"not all arguments converted"):
|
||||||
raise ProgrammingError, m.args[0]
|
raise ProgrammingError, msg.args[0]
|
||||||
escape = escape_dict
|
escape = escape_dict
|
||||||
q = [query % escape(args[0], qc)]
|
q = [query % escape(args[0], qc)]
|
||||||
qv = query[p:]
|
qv = query[p:]
|
||||||
@ -259,6 +266,10 @@ class CursorStoreResultMixIn:
|
|||||||
|
|
||||||
def _get_result(self): return self.connection.db.store_result()
|
def _get_result(self): return self.connection.db.store_result()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.connection = None
|
||||||
|
del self._rows
|
||||||
|
|
||||||
def _query(self, q):
|
def _query(self, q):
|
||||||
self.connection._acquire()
|
self.connection._acquire()
|
||||||
try:
|
try:
|
||||||
@ -345,17 +356,11 @@ class CursorUseResultMixIn:
|
|||||||
|
|
||||||
class CursorTupleRowsMixIn:
|
class CursorTupleRowsMixIn:
|
||||||
|
|
||||||
def _fetch_row(self): return self._result.fetch(1)[0]
|
def _fetch_row(self): return self._result.fetch_row(1)[0]
|
||||||
|
|
||||||
def _fetch_rows(self, size): return self._result.fetch(size)
|
def _fetch_rows(self, size): return self._result.fetch_row(size)
|
||||||
|
|
||||||
def _fetch_all_rows(self):
|
def _fetch_all_rows(self): return _fetchall(self._result, self.arraysize)
|
||||||
r = list(self._result.fetch(self.arraysize))
|
|
||||||
while len(r) >= self.arraysize:
|
|
||||||
rows = self._result.fetch(self.arraysize)
|
|
||||||
if not rows: break
|
|
||||||
r.extend(list(rows))
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
class CursorDictRowsMixIn:
|
class CursorDictRowsMixIn:
|
||||||
@ -364,13 +369,7 @@ class CursorDictRowsMixIn:
|
|||||||
|
|
||||||
def _fetch_rows(self, size): return self._result.fetch(size, 1)
|
def _fetch_rows(self, size): return self._result.fetch(size, 1)
|
||||||
|
|
||||||
def _fetch_all_rows(self):
|
def _fetch_all_rows(self): return _fetchall(self._result, self.arraysize, 1)
|
||||||
r = list(self._result.fetch(self.arraysize, 1))
|
|
||||||
while len(r) >= self.arraysize:
|
|
||||||
rows = self._result.fetch(self.arraysize, 1)
|
|
||||||
if not rows: break
|
|
||||||
r.extend(list(rows))
|
|
||||||
return r
|
|
||||||
|
|
||||||
## XXX Deprecated
|
## XXX Deprecated
|
||||||
|
|
||||||
@ -481,10 +480,10 @@ class Connection:
|
|||||||
def get_server_info(self): return self.db.get_server_info()
|
def get_server_info(self): return self.db.get_server_info()
|
||||||
def info(self): return self.db.info()
|
def info(self): return self.db.info()
|
||||||
def kill(self, p): return self.db.kill(p)
|
def kill(self, p): return self.db.kill(p)
|
||||||
def list_dbs(self): return self.db.list_dbs().fetch_all_rows()
|
def list_dbs(self): return _fetchall(self.db.list_dbs())
|
||||||
def list_fields(self, table): return self.db.list_fields(table).fetch_all_rows()
|
def list_fields(self, table): return _fetchall(self.db.list_fields(table))
|
||||||
def list_processes(self): return self.db.list_processes().fetch_all_rows()
|
def list_processes(self): return _fetchall(self.db.list_processes())
|
||||||
def list_tables(self, db): return self.db.list_tables(db).fetch_all_rows()
|
def list_tables(self, db): return _fetchall(self.db.list_tables(db))
|
||||||
def field_count(self): return self.db.field_count()
|
def field_count(self): return self.db.field_count()
|
||||||
num_fields = field_count # used prior to MySQL-3.22.24
|
num_fields = field_count # used prior to MySQL-3.22.24
|
||||||
def ping(self): return self.db.ping()
|
def ping(self): return self.db.ping()
|
||||||
|
@ -130,6 +130,9 @@ information, see the MySQL documentation. The documentation for this
|
|||||||
module is intentionally weak because you probably should use the
|
module is intentionally weak because you probably should use the
|
||||||
higher-level <ref id="MySQLdb"> module. If you really need it, use the
|
higher-level <ref id="MySQLdb"> module. If you really need it, use the
|
||||||
standard MySQL docs and transliterate as necessary.
|
standard MySQL docs and transliterate as necessary.
|
||||||
|
<p>Compatibility note: As of 0.2.2, the various fetch_rowXXX() cursor
|
||||||
|
methods have been combined into a single fetch_row([n=1[,how=0]])
|
||||||
|
method. See the built-in module documentation for more details.
|
||||||
<p>
|
<p>
|
||||||
The C API has been wrapped in an object-oriented way. The only MySQL
|
The C API has been wrapped in an object-oriented way. The only MySQL
|
||||||
data structures which are implemented are the <tt>MYSQL</tt> (database
|
data structures which are implemented are the <tt>MYSQL</tt> (database
|
||||||
@ -154,12 +157,7 @@ use is explicitly non-portable.
|
|||||||
@ <tt>mysql_debug()</tt> | <tt>_mysql.debug()</tt>
|
@ <tt>mysql_debug()</tt> | <tt>_mysql.debug()</tt>
|
||||||
@ <tt>mysql_dump_debug_info</tt> | <tt>conn.dump_debug_info()</tt>
|
@ <tt>mysql_dump_debug_info</tt> | <tt>conn.dump_debug_info()</tt>
|
||||||
@ <tt>mysql_escape_string()</tt> | <tt>_mysql.escape_string()</tt>
|
@ <tt>mysql_escape_string()</tt> | <tt>_mysql.escape_string()</tt>
|
||||||
@ <tt>mysql_fetch_row()</tt> | <tt>result.fetch_row()<newline>
|
@ <tt>mysql_fetch_row()</tt> | <tt>result.fetch_row()</tt>
|
||||||
result_fetch_row_as_dict()<newline>
|
|
||||||
result.fetch_rows()<newline>
|
|
||||||
result.fetch_rows_as_dict()<newline>
|
|
||||||
result.fetch_all_rows()<newline>
|
|
||||||
result.fetch_all_rows_as_dict()</tt>
|
|
||||||
@ <tt>mysql_get_client_info()</tt> | <tt>_mysql.get_client_info()</tt>
|
@ <tt>mysql_get_client_info()</tt> | <tt>_mysql.get_client_info()</tt>
|
||||||
@ <tt>mysql_get_host_info()</tt> | <tt>conn.get_host_info()</tt>
|
@ <tt>mysql_get_host_info()</tt> | <tt>conn.get_host_info()</tt>
|
||||||
@ <tt>mysql_get_proto_info()</tt> | <tt>conn.get_proto_info()</tt>
|
@ <tt>mysql_get_proto_info()</tt> | <tt>conn.get_proto_info()</tt>
|
||||||
|
@ -3,9 +3,7 @@
|
|||||||
# Adjust -L and -I as necessary for your local configuration.
|
# Adjust -L and -I as necessary for your local configuration.
|
||||||
# If you have dynamic MySQL libraries, they will need to be on your
|
# If you have dynamic MySQL libraries, they will need to be on your
|
||||||
# LD_LIBRARY_PATH at runtime.
|
# LD_LIBRARY_PATH at runtime.
|
||||||
_mysql _mysqlmodule.c -L/usr/lib/mysql -I/usr/include/mysql -lmysqlclient
|
# I find that 3.23 requires libz. It probably won't hurt earlier versions.
|
||||||
|
|
||||||
# I find that 3.23 requires libz.
|
|
||||||
_mysql _mysqlmodule.c -L/usr/lib/mysql -I/usr/include/mysql -lmysqlclient -lz
|
_mysql _mysqlmodule.c -L/usr/lib/mysql -I/usr/include/mysql -lmysqlclient -lz
|
||||||
|
|
||||||
# Uncomment for Windows
|
# Uncomment for Windows
|
||||||
|
@ -578,19 +578,13 @@ _mysql_escape_row(self, args)
|
|||||||
PyObject *o=NULL, *d=NULL, *r=NULL, *item, *quoted,
|
PyObject *o=NULL, *d=NULL, *r=NULL, *item, *quoted,
|
||||||
*itemtype, *itemconv;
|
*itemtype, *itemconv;
|
||||||
int i, n;
|
int i, n;
|
||||||
if (!PyArg_ParseTuple(args, "OO:escape_row", &o, &d)) goto error;
|
if (!PyArg_ParseTuple(args, "O!O!:escape_row", &PyTuple_Type, &o,
|
||||||
if (!PySequence_Check(o)) {
|
&PyDict_Type, &d))
|
||||||
PyErr_SetString(PyExc_TypeError, "sequence required");
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
if (!PyMapping_Check(d)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "mapping required");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (!(n = PyObject_Length(o))) goto error;
|
if (!(n = PyObject_Length(o))) goto error;
|
||||||
if (!(r = PyTuple_New(n))) goto error;
|
if (!(r = PyTuple_New(n))) goto error;
|
||||||
for (i=0; i<n; i++) {
|
for (i=0; i<n; i++) {
|
||||||
if (!(item = PySequence_GetItem(o, i))) goto error;
|
item = PyTuple_GET_ITEM(o, i);
|
||||||
if (!(itemtype = PyObject_Type(item)))
|
if (!(itemtype = PyObject_Type(item)))
|
||||||
goto error;
|
goto error;
|
||||||
itemconv = PyObject_GetItem(d, itemtype);
|
itemconv = PyObject_GetItem(d, itemtype);
|
||||||
@ -608,7 +602,6 @@ _mysql_escape_row(self, args)
|
|||||||
quoted = PyObject_CallFunction(itemconv, "O", item);
|
quoted = PyObject_CallFunction(itemconv, "O", item);
|
||||||
Py_DECREF(itemconv);
|
Py_DECREF(itemconv);
|
||||||
if (!quoted) goto error;
|
if (!quoted) goto error;
|
||||||
Py_DECREF(item);
|
|
||||||
PyTuple_SET_ITEM(r, i, quoted);
|
PyTuple_SET_ITEM(r, i, quoted);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
@ -799,12 +792,12 @@ _mysql_row_to_dict_old(self, row)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_mysql_ResultObject_fetch(self, args, kwargs)
|
_mysql_ResultObject_fetch_row(self, args, kwargs)
|
||||||
_mysql_ResultObject *self;
|
_mysql_ResultObject *self;
|
||||||
PyObject *args, *kwargs;
|
PyObject *args, *kwargs;
|
||||||
{
|
{
|
||||||
typedef PyObject *_PYFUNC();
|
typedef PyObject *_PYFUNC();
|
||||||
static char *kwlist[] = { "maxrows", "as_dict", NULL };
|
static char *kwlist[] = { "maxrows", "how", NULL };
|
||||||
static _PYFUNC *row_converters[] =
|
static _PYFUNC *row_converters[] =
|
||||||
{
|
{
|
||||||
_mysql_row_to_tuple,
|
_mysql_row_to_tuple,
|
||||||
@ -812,18 +805,18 @@ _mysql_ResultObject_fetch(self, args, kwargs)
|
|||||||
_mysql_row_to_dict_old
|
_mysql_row_to_dict_old
|
||||||
};
|
};
|
||||||
_PYFUNC *convert_row;
|
_PYFUNC *convert_row;
|
||||||
unsigned int maxrows=1, as_dict=0, i;
|
unsigned int maxrows=1, how=0, i;
|
||||||
PyObject *r;
|
PyObject *r;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:fetch", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:fetch_row", kwlist,
|
||||||
&maxrows, &as_dict))
|
&maxrows, &how))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (as_dict < 0 || as_dict >= sizeof(row_converters)) {
|
if (how < 0 || how >= sizeof(row_converters)) {
|
||||||
PyErr_SetString(PyExc_ValueError, "as_dict out of range");
|
PyErr_SetString(PyExc_ValueError, "how out of range");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
convert_row = row_converters[as_dict];
|
convert_row = row_converters[how];
|
||||||
|
|
||||||
if (!(r = PyTuple_New(maxrows))) return NULL;
|
if (!(r = PyTuple_New(maxrows))) return NULL;
|
||||||
for (i = 0; i<maxrows; i++) {
|
for (i = 0; i<maxrows; i++) {
|
||||||
@ -835,8 +828,10 @@ _mysql_ResultObject_fetch(self, args, kwargs)
|
|||||||
row = mysql_fetch_row(self->result);
|
row = mysql_fetch_row(self->result);
|
||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
}
|
}
|
||||||
if (!row && mysql_errno(self->connection))
|
if (!row && mysql_errno(self->connection)) {
|
||||||
|
Py_XDECREF(r);
|
||||||
return _mysql_Exception(self->connection);
|
return _mysql_Exception(self->connection);
|
||||||
|
}
|
||||||
if (!row) {
|
if (!row) {
|
||||||
if (_PyTuple_Resize(&r, i, 0) == -1) goto error;
|
if (_PyTuple_Resize(&r, i, 0) == -1) goto error;
|
||||||
break;
|
break;
|
||||||
@ -1312,7 +1307,7 @@ static PyMethodDef _mysql_ResultObject_methods[] = {
|
|||||||
{"row_seek", (PyCFunction)_mysql_ResultObject_row_seek, 1},
|
{"row_seek", (PyCFunction)_mysql_ResultObject_row_seek, 1},
|
||||||
{"row_tell", (PyCFunction)_mysql_ResultObject_row_tell, 0},
|
{"row_tell", (PyCFunction)_mysql_ResultObject_row_tell, 0},
|
||||||
{"describe", (PyCFunction)_mysql_ResultObject_describe, 0},
|
{"describe", (PyCFunction)_mysql_ResultObject_describe, 0},
|
||||||
{"fetch", (PyCFunction)_mysql_ResultObject_fetch, METH_VARARGS | METH_KEYWORDS},
|
{"fetch_row", (PyCFunction)_mysql_ResultObject_fetch_row, METH_VARARGS | METH_KEYWORDS},
|
||||||
{"field_flags", (PyCFunction)_mysql_ResultObject_field_flags, 0},
|
{"field_flags", (PyCFunction)_mysql_ResultObject_field_flags, 0},
|
||||||
{"num_fields", (PyCFunction)_mysql_ResultObject_num_fields, 0},
|
{"num_fields", (PyCFunction)_mysql_ResultObject_num_fields, 0},
|
||||||
{"num_rows", (PyCFunction)_mysql_ResultObject_num_rows, 0},
|
{"num_rows", (PyCFunction)_mysql_ResultObject_num_rows, 0},
|
||||||
@ -1485,9 +1480,9 @@ FLAG_*, CLIENT_*, FIELD_TYPE_*, etc. constants are renamed to FLAG.*,\n\
|
|||||||
CLIENT.*, FIELD_TYPE.*, etc. Deprecated functions are NOT implemented.\n\
|
CLIENT.*, FIELD_TYPE.*, etc. Deprecated functions are NOT implemented.\n\
|
||||||
\n\
|
\n\
|
||||||
type_conv is a dictionary which maps FIELD_TYPE.* to Python functions\n\
|
type_conv is a dictionary which maps FIELD_TYPE.* to Python functions\n\
|
||||||
which convert a string to some value. This is used by the various\n\
|
which convert a string to some value. This is used by the fetch_row method.\n\
|
||||||
fetch methods. Types not mapped are returned as strings. Numbers are\n\
|
Types not mapped are returned as strings. Numbers are all converted\n\
|
||||||
all converted reasonably, except DECIMAL.\n\
|
reasonably, except DECIMAL.\n\
|
||||||
\n\
|
\n\
|
||||||
result.describe() produces a DB API description of the rows.\n\
|
result.describe() produces a DB API description of the rows.\n\
|
||||||
\n\
|
\n\
|
||||||
@ -1501,14 +1496,10 @@ mysql_escape_string() on them, and returns them as a tuple.\n\
|
|||||||
\n\
|
\n\
|
||||||
result.field_flags() returns the field flags for the result.\n\
|
result.field_flags() returns the field flags for the result.\n\
|
||||||
\n\
|
\n\
|
||||||
result.fetch_row() fetches the next row as a tuple of objects. MySQL\n\
|
result.fetch_row([n=0[, how=1]]) fetches up to n rows (default: n=1)\n\
|
||||||
returns strings, but fetch_row() does data conversion according to\n\
|
as a tuple of tuples (default: how=0) or dictionaries (how=1).\n\
|
||||||
type_conv.\n\
|
MySQL returns strings, but fetch_row() does data conversion\n\
|
||||||
\n\
|
according to type_conv.\n\
|
||||||
result.fetch_rows(n) is like fetch_row() but fetches up to n rows and\n\
|
|
||||||
returns a tuple of rows.\n\
|
|
||||||
\n\
|
|
||||||
result.fetch_all_rows() is like fetch_rows() but fetchs all rows.\n\
|
|
||||||
\n\
|
\n\
|
||||||
For everything else, check the MySQL docs." ;
|
For everything else, check the MySQL docs." ;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user