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>
#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
to the API published by the Python db-sig at
@ -41,21 +42,10 @@ from string import upper, split, join
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
_type_conv = { FIELD_TYPE.TINY: int,
FIELD_TYPE.SHORT: int,
FIELD_TYPE.LONG: int,
FIELD_TYPE.LONG: long,
FIELD_TYPE.FLOAT: float,
FIELD_TYPE.DOUBLE: float,
FIELD_TYPE.LONGLONG: long,
@ -70,6 +60,33 @@ def isDML(q):
def isDQL(q):
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:
"""This is the connection object for the mySQL database interface."""
def __init__(self, host, user, passwd, db):
@ -84,9 +101,10 @@ class Connection:
except MySQL.Error, msg:
raise error, msg
self.__curs = Cursor(self.__conn)
self._server_info = i = self.__conn.get_server_info()
self._server_version = int(i[0])*10000 + int(i[2:4])*100 + int(i[5:7])
self.__conn.query("SHOW VARIABLES")
self.__vars = {}
for k, v in self.__conn.store_result().fetch_row(0):
self.__vars[k] = v
def __del__(self):
self.close()
@ -109,14 +127,15 @@ class Connection:
def commit(self):
"""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):
"""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"
def callproc(self, params=None): pass
# These functions are just here so that every action that is
@ -205,12 +224,9 @@ class Cursor:
self.__res = self.__conn.query(
op % params[-1])
self.insert_id = self.__res.insert_id()
f = self.__res.fields()
except MySQL.Error, msg:
raise error, msg
self.__dict__['description'] = tuple(map(
lambda x: (x[0], _type[x[2]], x[3],
x[3]), f))
self.__dict__['description'] = self.__res.describe()
return None
else:
try:
@ -244,17 +260,10 @@ class Cursor:
def fetchall(self):
if not self.__res: raise error, "no query made yet."
try:
rows = r = list(self.__res.fetch_row(self.arraysize))
while 1:
rows = list(self.__res.fetch_row(self.arraysize))
if not rows: break
r.extend(rows)
return r
return self.__res.fetch_row(0)
except MySQL.Error, msg:
raise error, msg
def fetchoneDict(self):
"""This is not a standard part of Python DB API."""
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."""
if not self.__res: raise error, "no query made yet."
try:
rows = r = list(self.__res.fetch_row(self.arraysize, 2))
while 1:
rows = list(self.__res.fetch_row(self.arraysize, 2))
if not rows: break
r.extend(rows)
return r
return self.__res.fetch_row(0,2)
except MySQL.Error, msg:
raise error, msg
def setinputsizes(self, sizes): pass
def setoutputsize(self, size, col=None): pass

View File

@ -19,9 +19,7 @@ You have two basic options:
<p>
<enum>
<item>
Modify the compiler flags in Setup so that it links against the static
library. Probably <tt/-static/ will do this for gcc/egcs; YMMV for
other C compilers.
Modify setup.py so that it links against the static library; see the comments.
<item>
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
@ -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.
<sect1>ImportError: ./_mysqlmodule.so: undefined symbol: uncompress
<sect1>./_mysqlmodule.c:33: mysql.h: No such file or directory
<P>
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
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
<tt/_mysqlmodule.so/. However, if you link against the static MySQL
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...
<P>Say no more.
<P>There is a <tt/compile.py/ script which supposedly gets the job done
for Windows, but I can't test it.
<P>I don't use Windows. setup.py is supposed to work for building.
There may also be a link to some user-contributed binaries on the web site.
</sect1>
<sect>
Trouble with ZMySQLDA
<p>Not supported. By me, at least. There is a new version on
<htmlurl url="http://www.zope.org" name="www.zope.org">
that supports MySQLdb without any patching. Use that.
<p>What? ZMySQLDA never fails! Well, actually, I just don't have any
good questions yet. Except: Install MySQLdb first, and then untar
the ZMySQLDA source into your Zope home, and restart Zope.
<sect>Using MySQLdb
<p>
MySQLdb is a
<htmlurl url="http://www.python.org/topics/database/DatabaseAPI-2.0.html"
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
<htmlurl url="http://starship.python.net/crew/adustman/MySQLdb.html"
<htmlurl url="http://dustman.net/andy/python/MySQLdb/doc/MySQLdb.html"
name="MySQLdb documentation">.
<sect1>What do I do if I am completely clueless?
<p>Get a clue. Clues have been provided in the <tt/examples/ directory
@ -97,18 +95,15 @@ results = c.fetchall()
</code>
<sect1>But MySQL doesn't have cursors!
<p>True enough. MySQLdb fakes it, though, because the spec requires it.
<sect1>cursor.rollback() is missing!
<p>MySQL doesn't do transactions. <tt/cursor.rollback()/ is supposed to
roll back (cancel) the current transaction. If you really need to do
this, then you definitely want <tt/cursor.rollback()/ to fail, because
it can't do what you want it to do.
<sect1>cursor.rollback() always fails!
<p>MySQL now supports transactions using BDB tables.
If your server doesn't support them, rollbacks will always fail, as they should,
because it can't do what you asked.
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
to the database, <em/does/ exist and always succeeds, because MySQL
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?
<P>Short answer: Don't, if you can avoid it. Your program will not
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
<tt/db.select_db(newdb)/ where <tt/db/ is your Connection object.
<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
isn't necessary for Zope's purposes.
<enum>

View File

@ -53,7 +53,7 @@ quote_conv = { types.IntType: Thing2Str,
type_conv = { FIELD_TYPE.TINY: int,
FIELD_TYPE.SHORT: int,
FIELD_TYPE.LONG: int,
FIELD_TYPE.LONG: long,
FIELD_TYPE.FLOAT: float,
FIELD_TYPE.DOUBLE: float,
FIELD_TYPE.LONGLONG: long,
@ -144,14 +144,6 @@ def Binary(x): return str(x)
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:
"""A base for Cursor classes. Useful attributes:
@ -256,6 +248,14 @@ class BaseCursor:
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:
@ -363,16 +363,8 @@ class CursorTupleRowsMixIn:
_fetch_type = 0
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 _fetchall(self._result, self.arraysize, self._fetch_type)
class CursorDictRowsMixIn(CursorTupleRowsMixIn):
class CursorDictRowsMixIn:
_fetch_type = 1
@ -453,9 +445,11 @@ class Connection:
self.cursorclass = Cursor
self.db = apply(connect, (), kwargs)
self.quote_conv[types.StringType] = self.Thing2Literal
self._server_info = self.db.get_server_info()
i = map(int, split(split(self._server_info, '-')[0],'.'))
self._server_version = i[0]*10000 + i[1]*100 + i[2]
self.db.query('show variables')
r = self.db.store_result()
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:
@ -473,11 +467,13 @@ class Connection:
def commit(self):
"""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):
"""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"
def cursor(self, cursorclass=None):
@ -496,10 +492,10 @@ class Connection:
def get_server_info(self): return self.db.get_server_info()
def info(self): return self.db.info()
def kill(self, p): return self.db.kill(p)
def list_dbs(self): return _fetchall(self.db.list_dbs())
def list_fields(self, table): return _fetchall(self.db.list_fields(table))
def list_processes(self): return _fetchall(self.db.list_processes())
def list_tables(self, db): return _fetchall(self.db.list_tables(db))
def list_dbs(self): return self.db.list_dbs().fetch_row(0)
def list_fields(self, table): return self.db.list_fields(table).fetch_row(0)
def list_processes(self): return self.db.list_processes().fetch_row(0)
def list_tables(self, db): return self.db.list_tables(db).fetch_row(0)
def field_count(self): return self.db.field_count()
num_fields = field_count # used prior to MySQL-3.22.24
def ping(self): return self.db.ping()

View File

@ -23,14 +23,21 @@ charge under a license derived from the Python license.
<p>
<sect2>Linux/UNIX
<p>
This module is developed on RedHat Linux 5.2 for Intel. It should build without
much trouble on most UNIX-like platforms by using the <tt/build.py/ script.
This module is developed on RedHat Linux (currently 7.0)
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.)
<p>
Windows is <em/not/ a supported platform.
However, the <tt/compile.py/ script
However, the <tt/setup.py/ script
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.
<sect1>Python
<p>
@ -57,19 +64,19 @@ type.
<sect2>MySQL-3.23
<p>
MySQLdb has only been lightly tested.
MySQL-3.23 is presently in beta (testing) release. Several API
MySQL-3.23 is presently in gamma (stable prerelease). Several API
additions have been made so far. These will be incorporated into
MySQLdb as work progresses. As of 3.23.15, transactions are supported
in MySQL using BDB tables. MySQLdb (0.2.2 and up) detects the
server version upon connection and will issue <tt/COMMIT/ and <tt/ROLLBACK/
MySQLdb as work progresses. As of 3.23.30, transactions are supported
in MySQL using BDB tables. MySQLdb (0.3.0 and up) detects the
presence of BDB table support
upon connection and will issue <tt/COMMIT/ and <tt/ROLLBACK/
statements when appropriate. Note that MySQL operates in
<tt/AUTOCOMMIT/ mode by default; you will have to issue SQL to
change this.
<sect1>DateTime
<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
it for date-related objects. Otherwise, these will be returned to
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>
both exist and silently do nothing <ref id="rollback" name="(danger!)">
| <tt>db.commit()</tt> and <tt>db.rollback()</tt> work if the MySQL
client library can perform transactions; otherwise <tt>db.rollback()</tt>
is not defined
server can perform transactions; otherwise <tt>db.rollback()</tt>
always fails
<caption>Mysqldb to MySQLdb changes</tabular></table>
<sect1>Zope and ZMySQLDA
<p>I'm not distributing a ZMySQLDA patch any more. Somebody else
has written a ZMySQLDA that works with MySQLdb. Find it at
<htmlurl url="http://www.zope.org/" name="the Zope home site">.
<p>I wrote a <htmlurl url="http://dustman.net/andy/python/ZMySQLDA" name="ZMySQLDA"> for use with MySQLdb.
<sect1>Documentation
<p>The web page documentation may be slightly ahead of the latest 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
higher-level <ref id="MySQLdb"> module. If you really need it, use the
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]])
method. See the built-in module documentation for more details.
<p>

View File

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

View File

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