Update docs.

result.fetch_row(0,how) returns all rows of the rsult set as a tuple.
This commit is contained in:
adustman
2001-01-27 02:32:00 +00:00
parent 57319a3928
commit d480ad766a
6 changed files with 175 additions and 135 deletions

View File

@ -1,5 +1,6 @@
#author: James Henstridge <james@daa.com.au> #author: James Henstridge <james@daa.com.au>
#adapted to _mysql by Andy Dustman <adustman@comstar.net> #adapted to _mysql by Andy Dustman <andy@dustman.net>
#under no circumstances should you bug James about this!!!
"""This is a class that implements an interface to mySQL databases, conforming """This is a class that implements an interface to mySQL databases, conforming
to the API published by the Python db-sig at to the API published by the Python db-sig at
@ -41,21 +42,10 @@ from string import upper, split, join
error = 'mysqldb.error' error = 'mysqldb.error'
_type = {}
for a in ('char', 'varchar', 'string', 'unhandled', '????'):
_type[a] = 'STRING'
for a in ('tiny blob', 'medium blob', 'long blob', 'blob'):
_type[a] = 'RAW'
for a in ('short', 'long', 'float', 'double', 'decimal'):
_type[a] = 'NUMBER'
for a in ('date', 'time', 'datetime', 'timestamp'):
_type[a] = 'DATE'
del a
from _mysql import FIELD_TYPE from _mysql import FIELD_TYPE
_type_conv = { FIELD_TYPE.TINY: int, _type_conv = { FIELD_TYPE.TINY: int,
FIELD_TYPE.SHORT: int, FIELD_TYPE.SHORT: int,
FIELD_TYPE.LONG: int, FIELD_TYPE.LONG: long,
FIELD_TYPE.FLOAT: float, FIELD_TYPE.FLOAT: float,
FIELD_TYPE.DOUBLE: float, FIELD_TYPE.DOUBLE: float,
FIELD_TYPE.LONGLONG: long, FIELD_TYPE.LONGLONG: long,
@ -70,6 +60,33 @@ def isDML(q):
def isDQL(q): def isDQL(q):
return upper(split(q)[0]) in ('SELECT', 'SHOW', 'DESC', 'DESCRIBE') return upper(split(q)[0]) in ('SELECT', 'SHOW', 'DESC', 'DESCRIBE')
class DBAPITypeObject:
def __init__(self,*values):
self.values = values
def __cmp__(self,other):
if other in self.values:
return 0
if other < self.values:
return 1
else:
return -1
_Set = DBAPITypeObject
STRING = _Set(FIELD_TYPE.CHAR, FIELD_TYPE.ENUM, FIELD_TYPE.INTERVAL,
FIELD_TYPE.SET, FIELD_TYPE.STRING, FIELD_TYPE.VAR_STRING)
BINARY = _Set(FIELD_TYPE.BLOB, FIELD_TYPE.LONG_BLOB, FIELD_TYPE.MEDIUM_BLOB,
FIELD_TYPE.TINY_BLOB)
NUMBER = _Set(FIELD_TYPE.DECIMAL, FIELD_TYPE.DOUBLE, FIELD_TYPE.FLOAT,
FIELD_TYPE.INT24, FIELD_TYPE.LONG, FIELD_TYPE.LONGLONG,
FIELD_TYPE.TINY, FIELD_TYPE.YEAR)
DATE = _Set(FIELD_TYPE.DATE, FIELD_TYPE.NEWDATE)
TIME = _Set(FIELD_TYPE.TIME)
TIMESTAMP = _Set(FIELD_TYPE.TIMESTAMP, FIELD_TYPE.DATETIME)
ROWID = _Set()
class Connection: class Connection:
"""This is the connection object for the mySQL database interface.""" """This is the connection object for the mySQL database interface."""
def __init__(self, host, user, passwd, db): def __init__(self, host, user, passwd, db):
@ -84,9 +101,10 @@ class Connection:
except MySQL.Error, msg: except MySQL.Error, msg:
raise error, msg raise error, msg
self.__curs = Cursor(self.__conn) self.__curs = Cursor(self.__conn)
self._server_info = i = self.__conn.get_server_info() self.__conn.query("SHOW VARIABLES")
self._server_version = int(i[0])*10000 + int(i[2:4])*100 + int(i[5:7]) self.__vars = {}
for k, v in self.__conn.store_result().fetch_row(0):
self.__vars[k] = v
def __del__(self): def __del__(self):
self.close() self.close()
@ -109,14 +127,15 @@ class Connection:
def commit(self): def commit(self):
"""Commit the current transaction.""" """Commit the current transaction."""
if self._server_version > 32315: self.__conn.query("COMMIT") if self.__vars.get('have_bdb', 'NO') == 'YES':
self.__conn.query("COMMIT")
def rollback(self): def rollback(self):
"""Rollback the current transaction.""" """Rollback the current transaction."""
if self._server_version > 32315: self.__conn.query("ROLLBACK") if self.__vars.get('have_bdb', 'NO') == 'YES':
self.__conn.query("ROLLBACK")
else: raise error, "Not supported by server" else: raise error, "Not supported by server"
def callproc(self, params=None): pass def callproc(self, params=None): pass
# These functions are just here so that every action that is # These functions are just here so that every action that is
@ -205,12 +224,9 @@ class Cursor:
self.__res = self.__conn.query( self.__res = self.__conn.query(
op % params[-1]) op % params[-1])
self.insert_id = self.__res.insert_id() self.insert_id = self.__res.insert_id()
f = self.__res.fields()
except MySQL.Error, msg: except MySQL.Error, msg:
raise error, msg raise error, msg
self.__dict__['description'] = tuple(map( self.__dict__['description'] = self.__res.describe()
lambda x: (x[0], _type[x[2]], x[3],
x[3]), f))
return None return None
else: else:
try: try:
@ -244,17 +260,10 @@ class Cursor:
def fetchall(self): def fetchall(self):
if not self.__res: raise error, "no query made yet." if not self.__res: raise error, "no query made yet."
try: try:
rows = r = list(self.__res.fetch_row(self.arraysize)) return self.__res.fetch_row(0)
while 1:
rows = list(self.__res.fetch_row(self.arraysize))
if not rows: break
r.extend(rows)
return r
except MySQL.Error, msg: except MySQL.Error, msg:
raise error, msg raise error, msg
def fetchoneDict(self): def fetchoneDict(self):
"""This is not a standard part of Python DB API.""" """This is not a standard part of Python DB API."""
if not self.__res: raise error, "no query made yet." if not self.__res: raise error, "no query made yet."
@ -275,17 +284,10 @@ class Cursor:
"""This is not a standard part of Python DB API.""" """This is not a standard part of Python DB API."""
if not self.__res: raise error, "no query made yet." if not self.__res: raise error, "no query made yet."
try: try:
rows = r = list(self.__res.fetch_row(self.arraysize, 2)) return self.__res.fetch_row(0,2)
while 1:
rows = list(self.__res.fetch_row(self.arraysize, 2))
if not rows: break
r.extend(rows)
return r
except MySQL.Error, msg: except MySQL.Error, msg:
raise error, msg raise error, msg
def setinputsizes(self, sizes): pass def setinputsizes(self, sizes): pass
def setoutputsize(self, size, col=None): pass def setoutputsize(self, size, col=None): pass

View File

@ -19,9 +19,7 @@ You have two basic options:
<p> <p>
<enum> <enum>
<item> <item>
Modify the compiler flags in Setup so that it links against the static Modify setup.py so that it links against the static library; see the comments.
library. Probably <tt/-static/ will do this for gcc/egcs; YMMV for
other C compilers.
<item> <item>
Change your system environment so that the MySQL libraries are on Change your system environment so that the MySQL libraries are on
your loader path. With Linux, you can modify <tt>/etc/ld.so.conf</tt> (see your loader path. With Linux, you can modify <tt>/etc/ld.so.conf</tt> (see
@ -38,13 +36,13 @@ linking against an earlier version. You may also have more than one version
installed. Get Python 1.5.2 from your vendor or python.org. installed. Get Python 1.5.2 from your vendor or python.org.
<sect1>ImportError: ./_mysqlmodule.so: undefined symbol: uncompress <sect1>ImportError: ./_mysqlmodule.so: undefined symbol: uncompress
<sect1>./_mysqlmodule.c:33: mysql.h: No such file or directory
<P> <P>
It seems that MySQL-3.23 client libraries require libz for gzip It seems that MySQL-3.23 client libraries require libz for gzip
compression. Add -lz to the link line in Setup. compression. setup.py should add this automatically.
<sect1>./_mysqlmodule.c:33: mysql.h: No such file or directory
<P>The include path (-I) to your MySQL include files is wrong; modify <P>The include path (-I) to your MySQL include files is wrong; modify
Setup. OR: You don't have the MySQL development stuff loaded. If you setup.py. OR: You don't have the MySQL development stuff loaded. If you
are using the Red Hat RPMs, you need the <tt/MySQL-devel/ RPM to compile are using the Red Hat RPMs, you need the <tt/MySQL-devel/ RPM to compile
<tt/_mysqlmodule.so/. However, if you link against the static MySQL <tt/_mysqlmodule.so/. However, if you link against the static MySQL
libraries (see above), you can install <tt/_mysqlmodule.so/ on a system libraries (see above), you can install <tt/_mysqlmodule.so/ on a system
@ -52,21 +50,21 @@ that does not have the MySQL client libraries (<tt/libmysqlclient/).
<sect1>I'm using Windows... <sect1>I'm using Windows...
<P>Say no more. <P>Say no more.
<P>There is a <tt/compile.py/ script which supposedly gets the job done <P>I don't use Windows. setup.py is supposed to work for building.
for Windows, but I can't test it. There may also be a link to some user-contributed binaries on the web site.
</sect1> </sect1>
<sect> <sect>
Trouble with ZMySQLDA Trouble with ZMySQLDA
<p>Not supported. By me, at least. There is a new version on <p>What? ZMySQLDA never fails! Well, actually, I just don't have any
<htmlurl url="http://www.zope.org" name="www.zope.org"> good questions yet. Except: Install MySQLdb first, and then untar
that supports MySQLdb without any patching. Use that. the ZMySQLDA source into your Zope home, and restart Zope.
<sect>Using MySQLdb <sect>Using MySQLdb
<p> <p>
MySQLdb is a MySQLdb is a
<htmlurl url="http://www.python.org/topics/database/DatabaseAPI-2.0.html" <htmlurl url="http://www.python.org/topics/database/DatabaseAPI-2.0.html"
name="Python Database API Specification 2.0"> database module, so you name="Python Database API Specification 2.0"> database module, so you
should be familiar with the spec. Deviations from the spec are documented in the should be familiar with the spec. Deviations from the spec are documented in the
<htmlurl url="http://starship.python.net/crew/adustman/MySQLdb.html" <htmlurl url="http://dustman.net/andy/python/MySQLdb/doc/MySQLdb.html"
name="MySQLdb documentation">. name="MySQLdb documentation">.
<sect1>What do I do if I am completely clueless? <sect1>What do I do if I am completely clueless?
<p>Get a clue. Clues have been provided in the <tt/examples/ directory <p>Get a clue. Clues have been provided in the <tt/examples/ directory
@ -97,18 +95,15 @@ results = c.fetchall()
</code> </code>
<sect1>But MySQL doesn't have cursors! <sect1>But MySQL doesn't have cursors!
<p>True enough. MySQLdb fakes it, though, because the spec requires it. <p>True enough. MySQLdb fakes it, though, because the spec requires it.
<sect1>cursor.rollback() is missing! <sect1>cursor.rollback() always fails!
<p>MySQL doesn't do transactions. <tt/cursor.rollback()/ is supposed to <p>MySQL now supports transactions using BDB tables.
roll back (cancel) the current transaction. If you really need to do If your server doesn't support them, rollbacks will always fail, as they should,
this, then you definitely want <tt/cursor.rollback()/ to fail, because because it can't do what you asked.
it can't do what you want it to do. Even if your server does support them, rollbacks will fail if you
modified any non-BDB tables.
<p>OTOH, <tt/cursor.commit()/, which attempts to commit the transaction <p>OTOH, <tt/cursor.commit()/, which attempts to commit the transaction
to the database, <em/does/ exist and always succeeds, because MySQL to the database, <em/does/ exist and always succeeds, because MySQL
essentially is always in auto-commit mode. essentially is always in auto-commit mode.
<p>MySQL-3.23 will, sometime in the near future, support transactions.
When this happens, <tt/cursor.commit()/ will actually do something
(and may fail if MySQL returns an error or warning condition), and
<tt/cursor.rollback()/ will actually exist and undo the current transaction.
<sect1>How do I use some of the special MySQL features? <sect1>How do I use some of the special MySQL features?
<P>Short answer: Don't, if you can avoid it. Your program will not <P>Short answer: Don't, if you can avoid it. Your program will not
be portable to other databases. be portable to other databases.
@ -119,7 +114,7 @@ argument (the connection handle in the C API). So let's say you want to
use <tt/mysql_select_db(newdb)/. In MySQLdb, that's use <tt/mysql_select_db(newdb)/. In MySQLdb, that's
<tt/db.select_db(newdb)/ where <tt/db/ is your Connection object. <tt/db.select_db(newdb)/ where <tt/db/ is your Connection object.
<sect1>I still wanna use _mysql directly. <sect1>I still wanna use _mysql directly.
<p>Well, it <tt/may/ be appropriate in some cirumstances. The patched <p>Well, it <tt/may/ be appropriate in some cirumstances.
ZMySQLDA does this, because MySQLdb does a lot of type conversion that ZMySQLDA does this, because MySQLdb does a lot of type conversion that
isn't necessary for Zope's purposes. isn't necessary for Zope's purposes.
<enum> <enum>

View File

@ -53,7 +53,7 @@ quote_conv = { types.IntType: Thing2Str,
type_conv = { FIELD_TYPE.TINY: int, type_conv = { FIELD_TYPE.TINY: int,
FIELD_TYPE.SHORT: int, FIELD_TYPE.SHORT: int,
FIELD_TYPE.LONG: int, FIELD_TYPE.LONG: long,
FIELD_TYPE.FLOAT: float, FIELD_TYPE.FLOAT: float,
FIELD_TYPE.DOUBLE: float, FIELD_TYPE.DOUBLE: float,
FIELD_TYPE.LONGLONG: long, FIELD_TYPE.LONGLONG: long,
@ -144,14 +144,6 @@ def Binary(x): return str(x)
insert_values = re.compile(r'values\s(\(.+\))', re.IGNORECASE) insert_values = re.compile(r'values\s(\(.+\))', re.IGNORECASE)
def _fetchall(result, *args):
rows = r = list(apply(result.fetch_row, args))
while 1:
rows = apply(result.fetch_row, args)
if not rows: break
r.extend(list(rows))
return r
class BaseCursor: class BaseCursor:
"""A base for Cursor classes. Useful attributes: """A base for Cursor classes. Useful attributes:
@ -256,6 +248,14 @@ class BaseCursor:
def nextset(self): return None def nextset(self): return None
def _fetch_row(self): return self._result.fetch_row(1, self._fetch_type)[0]
def _fetch_rows(self, size):
return self._result.fetch_row(size, self._fetch_type)
def _fetch_all_rows(self):
return self._result.fetch_row(0, self._fetch_type)
class CursorWarningMixIn: class CursorWarningMixIn:
@ -363,16 +363,8 @@ class CursorTupleRowsMixIn:
_fetch_type = 0 _fetch_type = 0
def _fetch_row(self): return self._result.fetch_row(1, self._fetch_type)[0]
def _fetch_rows(self, size): class CursorDictRowsMixIn:
return self._result.fetch_row(size, self._fetch_type)
def _fetch_all_rows(self):
return _fetchall(self._result, self.arraysize, self._fetch_type)
class CursorDictRowsMixIn(CursorTupleRowsMixIn):
_fetch_type = 1 _fetch_type = 1
@ -453,9 +445,11 @@ class Connection:
self.cursorclass = Cursor self.cursorclass = Cursor
self.db = apply(connect, (), kwargs) self.db = apply(connect, (), kwargs)
self.quote_conv[types.StringType] = self.Thing2Literal self.quote_conv[types.StringType] = self.Thing2Literal
self._server_info = self.db.get_server_info() self.db.query('show variables')
i = map(int, split(split(self._server_info, '-')[0],'.')) r = self.db.store_result()
self._server_version = i[0]*10000 + i[1]*100 + i[2] vars = r.fetch_row(0)
self._server_vars = {}
for k,v in vars: self._server_vars[k] = v
if _threading: self.__lock = _threading.Lock() if _threading: self.__lock = _threading.Lock()
if _threading: if _threading:
@ -473,11 +467,13 @@ class Connection:
def commit(self): def commit(self):
"""Commit the current transaction.""" """Commit the current transaction."""
if self._server_version > 32315: self.db.query("COMMIT") if self._server_vars.get('have_bdb','NO') == 'YES':
self.db.query("COMMIT")
def rollback(self): def rollback(self):
"""Rollback the current transaction.""" """Rollback the current transaction."""
if self._server_version > 32315: self.db.query("ROLLBACK") if self._server_vars.get('have_bdb','NO') == 'YES':
self.db.query("ROLLBACK")
else: raise NotSupportedError, "Not supported by server" else: raise NotSupportedError, "Not supported by server"
def cursor(self, cursorclass=None): def cursor(self, cursorclass=None):
@ -496,10 +492,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 _fetchall(self.db.list_dbs()) def list_dbs(self): return self.db.list_dbs().fetch_row(0)
def list_fields(self, table): return _fetchall(self.db.list_fields(table)) def list_fields(self, table): return self.db.list_fields(table).fetch_row(0)
def list_processes(self): return _fetchall(self.db.list_processes()) def list_processes(self): return self.db.list_processes().fetch_row(0)
def list_tables(self, db): return _fetchall(self.db.list_tables(db)) def list_tables(self, db): return self.db.list_tables(db).fetch_row(0)
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()

View File

@ -23,14 +23,21 @@ charge under a license derived from the Python license.
<p> <p>
<sect2>Linux/UNIX <sect2>Linux/UNIX
<p> <p>
This module is developed on RedHat Linux 5.2 for Intel. It should build without This module is developed on RedHat Linux (currently 7.0)
much trouble on most UNIX-like platforms by using the <tt/build.py/ script. for Intel. It should build without
much trouble on most platforms by using the <tt/setup.py/ script.
Supposedly it builds on MacOS X.
Be aware that you need the Distutils package which comes with
Python 2.0. If you don't have it (i.e. you have Python 1.5.2), you
can find it over at <htmlurl url="http://www.python.org/" name="www.python.org">.
<sect2>Windows (3.11, 95, 98, NT, 2000, CE, BSOD, XYZ, etc.) <sect2>Windows (3.11, 95, 98, NT, 2000, CE, BSOD, XYZ, etc.)
<p> <p>
Windows is <em/not/ a supported platform. Windows is <em/not/ a supported platform.
However, the <tt/compile.py/ script However, the <tt/setup.py/ script
reportedly gets the job done. reportedly gets the job done.
Be aware that this is a user-contributed script; the author There is probably a link on the web page for getting a precompiled
Windows installer from someone or other.
Be aware that this is a user-contributed package; the author
cannot help you with compiling and running under Windows. cannot help you with compiling and running under Windows.
<sect1>Python <sect1>Python
<p> <p>
@ -57,19 +64,19 @@ type.
<sect2>MySQL-3.23 <sect2>MySQL-3.23
<p> <p>
MySQLdb has only been lightly tested. MySQL-3.23 is presently in gamma (stable prerelease). Several API
MySQL-3.23 is presently in beta (testing) release. Several API
additions have been made so far. These will be incorporated into additions have been made so far. These will be incorporated into
MySQLdb as work progresses. As of 3.23.15, transactions are supported MySQLdb as work progresses. As of 3.23.30, transactions are supported
in MySQL using BDB tables. MySQLdb (0.2.2 and up) detects the in MySQL using BDB tables. MySQLdb (0.3.0 and up) detects the
server version upon connection and will issue <tt/COMMIT/ and <tt/ROLLBACK/ presence of BDB table support
upon connection and will issue <tt/COMMIT/ and <tt/ROLLBACK/
statements when appropriate. Note that MySQL operates in statements when appropriate. Note that MySQL operates in
<tt/AUTOCOMMIT/ mode by default; you will have to issue SQL to <tt/AUTOCOMMIT/ mode by default; you will have to issue SQL to
change this. change this.
<sect1>DateTime <sect1>DateTime
<p>If you have the <htmlurl <p>If you have the <htmlurl
url="http://starship.skyport.net/~lemburg/mxDateTime.html" url="http://www.lemburg.com/files/python/mxDateTime.html"
name="DateTime"> module installed (recommended), MySQLdb will use name="DateTime"> module installed (recommended), MySQLdb will use
it for date-related objects. Otherwise, these will be returned to it for date-related objects. Otherwise, these will be returned to
Python as strings. You can also modify the type conversion Python as strings. You can also modify the type conversion
@ -109,14 +116,12 @@ with the same name; use SQL <tt/AS/ to rename fields.
@ Transactions | <tt>db.commit()</tt> and <tt>db.rollback()</tt> @ Transactions | <tt>db.commit()</tt> and <tt>db.rollback()</tt>
both exist and silently do nothing <ref id="rollback" name="(danger!)"> both exist and silently do nothing <ref id="rollback" name="(danger!)">
| <tt>db.commit()</tt> and <tt>db.rollback()</tt> work if the MySQL | <tt>db.commit()</tt> and <tt>db.rollback()</tt> work if the MySQL
client library can perform transactions; otherwise <tt>db.rollback()</tt> server can perform transactions; otherwise <tt>db.rollback()</tt>
is not defined always fails
<caption>Mysqldb to MySQLdb changes</tabular></table> <caption>Mysqldb to MySQLdb changes</tabular></table>
<sect1>Zope and ZMySQLDA <sect1>Zope and ZMySQLDA
<p>I'm not distributing a ZMySQLDA patch any more. Somebody else <p>I wrote a <htmlurl url="http://dustman.net/andy/python/ZMySQLDA" name="ZMySQLDA"> for use with MySQLdb.
has written a ZMySQLDA that works with MySQLdb. Find it at
<htmlurl url="http://www.zope.org/" name="the Zope home site">.
<sect1>Documentation <sect1>Documentation
<p>The web page documentation may be slightly ahead of the latest release <p>The web page documentation may be slightly ahead of the latest release
and may reflect features of the next release. and may reflect features of the next release.
@ -132,7 +137,7 @@ 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 <p>Compatibility note: As of 0.3.0, the various fetch_rowXXX() cursor
methods have been combined into a single fetch_row([n=1[,how=0]]) methods have been combined into a single fetch_row([n=1[,how=0]])
method. See the built-in module documentation for more details. method. See the built-in module documentation for more details.
<p> <p>

View File

@ -880,12 +880,14 @@ _mysql_row_to_dict_old(
v = _mysql_field_to_python(c, row[i], length[i]); v = _mysql_field_to_python(c, row[i], length[i]);
if (!v) goto error; if (!v) goto error;
{ {
int len; int len=0;
char buf[256]; char buf[256]="";
if (strlen(fields[i].table)) {
strncpy(buf, fields[i].table, 256); strncpy(buf, fields[i].table, 256);
len = strlen(buf); len = strlen(buf);
strncat(buf, ".", 256-len); strncat(buf, ".", 256-len);
len = strlen(buf); len = strlen(buf);
}
strncat(buf, fields[i].name, 256-len); strncat(buf, fields[i].name, 256-len);
PyMapping_SetItemString(r, buf, v); PyMapping_SetItemString(r, buf, v);
} }
@ -897,6 +899,45 @@ _mysql_row_to_dict_old(
return NULL; return NULL;
} }
typedef PyObject *_PYFUNC(_mysql_ResultObject *, MYSQL_ROW);
int
_mysql__fetch_row(
_mysql_ResultObject *self,
PyObject *r,
int skiprows,
int maxrows,
_PYFUNC *convert_row)
{
unsigned int i;
MYSQL_ROW row;
for (i = skiprows; i<(skiprows+maxrows); i++) {
PyObject *v;
if (!self->use)
row = mysql_fetch_row(self->result);
else {
Py_BEGIN_ALLOW_THREADS;
row = mysql_fetch_row(self->result);
Py_END_ALLOW_THREADS;
}
if (!row && mysql_errno(self->connection)) {
_mysql_Exception((_mysql_ConnectionObject *)self->conn);
goto error;
}
if (!row) {
if (_PyTuple_Resize(&r, i, 0) == -1) goto error;
break;
}
v = convert_row(self, row);
if (!v) goto error;
PyTuple_SET_ITEM(r, i, v);
}
return i-skiprows;
error:
return -1;
}
static PyObject * static PyObject *
_mysql_ResultObject_fetch_row( _mysql_ResultObject_fetch_row(
_mysql_ResultObject *self, _mysql_ResultObject *self,
@ -912,9 +953,8 @@ _mysql_ResultObject_fetch_row(
_mysql_row_to_dict_old _mysql_row_to_dict_old
}; };
_PYFUNC *convert_row; _PYFUNC *convert_row;
unsigned int maxrows=1, how=0, i; unsigned int maxrows=1, how=0, skiprows=0, rowsadded;
PyObject *r; PyObject *r=NULL;
MYSQL_ROW row;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:fetch_row", kwlist, if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii:fetch_row", kwlist,
&maxrows, &how)) &maxrows, &how))
@ -924,28 +964,30 @@ _mysql_ResultObject_fetch_row(
return NULL; return NULL;
} }
convert_row = row_converters[how]; convert_row = row_converters[how];
if (maxrows) {
if (!(r = PyTuple_New(maxrows))) return NULL; if (!(r = PyTuple_New(maxrows))) goto error;
for (i = 0; i<maxrows; i++) { rowsadded = _mysql__fetch_row(self, r, skiprows, maxrows,
PyObject *v; convert_row);
if (!self->use) if (rowsadded == -1) goto error;
row = mysql_fetch_row(self->result); } else {
else { if (self->use) {
Py_BEGIN_ALLOW_THREADS; maxrows = 1000;
row = mysql_fetch_row(self->result); if (!(r = PyTuple_New(maxrows))) goto error;
Py_END_ALLOW_THREADS; while (1) {
rowsadded = _mysql__fetch_row(self, r, skiprows,
maxrows, convert_row);
if (rowsadded == -1) goto error;
skiprows += rowsadded;
if (rowsadded < maxrows) break;
} }
if (!row && mysql_errno(self->connection)) { } else {
Py_XDECREF(r); /* XXX if overflow, maxrows<0? */
return _mysql_Exception((_mysql_ConnectionObject *)self->conn); maxrows = (int) 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;
} }
if (!row) {
if (_PyTuple_Resize(&r, i, 0) == -1) goto error;
break;
}
v = convert_row(self, row);
if (!v) goto error;
PyTuple_SET_ITEM(r, i, v);
} }
return r; return r;
error: error:

View File

@ -69,7 +69,7 @@ derived from the Python license.
setup (# Distribution meta-data setup (# Distribution meta-data
name = "MySQL-python", name = "MySQL-python",
version = "0.3.0", version = "0.3.2",
description = "An interface to MySQL", description = "An interface to MySQL",
long_description=long_description, long_description=long_description,
author = "Andy Dustman", author = "Andy Dustman",