pkg://MySQL-python-1.4-2.src.rpm:23421/MySQLmodule-1.4.tar.gz
info downloads
./MySQLmodule-1.4/ 40775 765 765 0 6605365776 11544 5 ustar www www ./MySQLmodule-1.4/Credits 100644 765 765 20076 6603125152 13160 0 ustar www www Original copyright notices from the top of the mySQLmodule-0.1.4
----------------------------------------------------------------
/*
An interface to the mySQL database system for Python
Copyright (C) 1997 Joseph Skinner <joe@earthlink.co.nz>
Query cursor code and some modifications
Copyright (C) 1997 James Henstridge <james@daa.com.au>
Based on mSQLmodule which was by the following people:
Portions copyright (C) 1995 Thawte Consulting, cc
(Those portions covered by the next copyright notice)
Portions copyright (C) 1994 Anthony Baxter.
*******************************************************************
Ported to mySQL Skinner (joe@earthlight.co.nz) Janurary 1997
-- STATUS : BETA
--VERSION 0.1.0
- converted source
- added support for some of the types not included in mSQL
- added support for return of auto_increment values
an auto_increment value is returned as a result from an insert
VERSION 0.1.2 (1997-04-02)
- added support for varchar
- added support for username and passwords
VERSION 0.1.4 (1997-09-09)
- added decimal and float types
- added a query cursor. (Mainly to support mysqldb - the Python
DB API module for MySQL) See New file.
- changed behavior so that currently unhandled types are returned
as strings, so that the python programmer can figure out what to
do with them.
-- TODO
- support timestamps
- support all unsupported mysql types
*/
/* This mSQLmodule copyright (it only applies to those sections):
******************************************************
*
* Based on a prior work by Anthony Baxter
* Updated, fixed and extended by David Gibson working for
* Thawte Consulting cc, South Africa.
*
* Copyright 1995 Thawte Consulting cc
* Portions copyright (C) 1994 Anthony Baxter.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this source file to use, copy, modify, merge, or publish it
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or in any new file that contains a substantial portion of
* this file.
*
* THE AUTHOR MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF
* THE SOFTWARE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT
* EXPRESS OR IMPLIED WARRANTY. THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE, STRICT LIABILITY OR
* ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
******************************************************
mSQLmodule ChangeLog:- (slightly mangled by msql2mysql)
Modified by David Gibson December 1995
- listdbs and listtables now return a list of strings
- new Python naming conventions introduced
- queries now return data types in native Python format (String,Float,Int)
- solved spurious 'function requires at least one argument' error: old
getargs would not handle optional arguments. ParseTuple is being used now.
(so method table has got 1's in now)
(old Parse routine still needed for subscript handling)
- mysql_free_result now called after query!
- assignment to subscript trapped correctly. Ditto len()
- added DbType to the module dictionary
- mySQL.error object introduced
******************************************************
*/
----- Original New file from mySQLmodule ---------------------------
Release 0.1.4 1997-09-09
Added Support for the following types
float -- from Mitch Chapman <mchapman@OhioEE.com>
decimal -- me (I had to do something in this release :-) )
Added a connect patch from Giles Francis Hall <ghall@interaccess.com>
I just thought you might want to have this small piece of code which
traps an connect() error. I was wondering what was happening with
my programs when they the SQL server was down yet things seemed to
go happily along their way returning empty data sets ;) ...
*****
if(!(mysql_connect(&newhandle, dbname, dbuser, dbpass))) {
PyErr_SetString(mySQLError, "connect(): could not connect to MySQL");
return NULL;
}
Added Support for the python dbi standard from
James Henstridge <james@daa.com.au>
These modifications by James Henstridge <james@daa.com.au>:
This release adds an extra object called a querycursor.
The querycursor object is used to look at a large result from a query.
It doesn't convert the complete result to a list, only converting the
sections asked for. They are created as a result from the querycursor
function.
ie curs = connection.querycursor('select * from table')
These objects have the following methods:
fields() -- Similar output to connection.listfields().
insert_id() -- Returns the insert ID of the query.
fetchall() -- Fetch a list of all the remaining records.
fetchone() -- Fetch the next record.
fetchmany(num) -- Fetch a list of at most num records.
seek(pos) -- set the cursor position in the result.
eof() -- returns true if there are no more records.
numrows() -- returns the number of rows in the result.
numfields() -- returns the number of fields in the result.
affectedrows() -- returns the number of affected rows. -1 for select
queries
If the query doesn't return a result, all but the last method will raise
an exception.
As a change to the behavior of the old functions, instead of not returning
`unhandled' field values, they are returned as strings, in the hope that
the python programmer will be able to find some sensible way of using them.
Also included in this distribution is mysqldb.py, which is a Python DB API
compliant interface to MySQL databases, written as a frontend to mySQLmodule.
Mysqldb should be used for new programs, since it makes them more portable
across different databases. More information on this specification can be
found at http://www.python.org/sigs/db-sig/DatabaseAPI.html
An example module mysqlshelve is included which uses mysqldb to implement an
object similar to Shelf, which stores the information in a MySQL table.
Release 0.1.3 1997-04-23
This code has been tested on a linux box using linux 2.1.55 libc6
and mysql 3.20.29
Bug Fixes
Fixes for my silly typos in timedate handling provided by
Karsten Thygesen <karthy@kom.auc.dk>
New commands
It includes the following new functionality.
create(db_name) create a new database
drop(db_name) drop a database
reload() reload the mysql tables
shutdown() shutdown mysql
Release 0.1.2 1997-04-03
New In this Release
Support for new mysql types
varchar
blobs
time
date
timedate
timestamp
Support for Username and Passwords
authentification is handled as part of the connect option
ie
import mySQL
db = mySQL.connect(<OPTIONS>)
where options can be either
nothing -- connect()
hostname -- connect('localhost')
hostname, username -- connect('localhost', 'fred')
hostname, username, password -- connect('localhost, 'fred','green')
IMPORTANT
The support for date and time will not work with earlier versions of
mysql which did not support these functions. Therefore these may be
disabled by changing the #define
#define INCLUDE_DATE_TIME_SUPPORT 1
to
#undef INCLUDE_DATE_TIME_SUPPORT
at the top the file.
----- Original Credits file from mySQLmodule ------------------------
All those people who have put word into the mySQL module
Monty -- lots of code and suggestions
James Henstridge <james@daa.com.au>) -- the new Python DB extensions
Mitch Chapman <mchapman@OhioEE.com> -- float support
Giles Francis Hall <ghall@interaccess.com> -- fix for connect bug
The orginal authors of the mSQL module
./MySQLmodule-1.4/MySQLmodule.c 100664 765 765 114613 6605365352 14214 0 ustar www www /*
A Python interface to the MySQL database.
Python: http://www.python.org
MySQL: http://www.tcx.se
Copyright (C) 1998 Joerg Senekowitsch <senekow@ibm.net>
Based on mySQLmodule-0.1.4 (see below)
WARNING: This code is not compatible with mySQLmodule-0.1.4!!!
This interface tested with Python 1.5.1 and MySQL 3.21.30
on Linux RH5.0 (kernel 2.0.33). It works for me, YMMV.
JS, May 1998
Version 1.4 (JS 10/03/1998):
- Another segfault fix from Richard Fish (rjf@estinc.com).
STH reference counting off by one for server side storage.
- Patch to return unsigned longs from Ladislav Lhotka (lhotka@jcu.cz).
If the mysql field has the UNSIGNED attribute set, we need to suppress
the sign bit evaluation and return a PyLong instead of a PyInt.
- The home-made escape_chars() has been replaced by a call to
mysql_escape_string(), requiring at least 3.21.30 for correct
operation.
- listfields() and fields() now return the information:
o usign - field has the UNSIGNED attribute set
- Unsigned fields return PyLongs instead of PyInts.
- Support compilation on NT systems by Nigel Head (nhead@houbits.com).
See README.NT for details.
Note: The NT port only works with MySQL version 3.22.8, while this
module has been developed for the 3.21 API. Thus, some of the
3.22 functionality is missing. In particular, the return
values of mysql_affected_rows() and mysql_insert_id() have
changed to my_ulonglong in 3.22, which will be represented by
this module as standard signed PyInt potentially resulting in
some odd behavior for DBs with more than 2**31-1 rows and/or
insert operations.
Version 1.3 (JS 08/18/1998):
- Fixed segfaults due to uninitialized field STH->res in DBH_query()
(Thanks to Grisha Trubetskoy)
- Added instructions on how to compile MySQLmodule as a shared module
(Thanks to Trond Eivind Glomsrød)
Version 1.2 (JS 07/16/1998):
- Error checking on all mysql API calls
- Tossed out useless includes which should make FreeBSD happy
- Added __doc__ string and changed DbType and ResType to DBH_Type and STH_Type
- DBH.do and DBH[...] now return affected_rows() if no result
- listdbs(), listtables(), listfields(), and listprocesses() now return
empty lists instead of None if there is no data.
- Added DBHObjects:
o close()
o insert_id()
- listfields() and fields() now return more information:
o pri - primary key field
o notnull - not null field
o auto_inc - auto_increment field
o ukey - unique key field
o mkey - multiple key field
Version 1.1a (JS 06/30/98) [never released]:
- Fixed bug in protoinfo()
- Additional error checking in
listdbs(), listtables(), listfields(), listprocesses()
Version 1.1 (JS 06/11/98):
- Cleaner error handling after discussion with Monty (thanks!)
- New feature:
o DBH.selectdb(string[,int]) will now take optional integer
parameter to switch between client side (0, default)
and server side (>0) result set storage. This should
improve the behavior of low memory clients. Note that
this affects server performance negatively.
o DBH.query(string[,int]) will allow overriding the DB
selected result set storage method on a per cursor basis.
Version 1.0a:
- Hopefully all possible errors (Python & MySQL) are caught and handled.
New features in version 1.0:
- Name change to 'MySQL' so that this module does not clash with the
old (incompatible) 'mySQL' module.
- Plugged huge memory leak in listdbs, listtables, and listfields
- Added wildcard argument to listdbs, listtables, and listfields
- Allow \0 in queries (for inserting images!)
- Added MySQLObjects:
o escape()
- Added DBHObjects:
o stat()
o clientinfo() [overwritten with module version string]
o serverinfo()
o hostinfo()
o protoinfo()
o listprocesses()
o do() [former 'query']
o query() [former 'querycursor']
- Added STHObjects:
o fetchrows([n]) [n<0: all records (default), n>0: only n records]
o fetchdict([n]) [same as fetchrows(). Returns list of dicts]
- Removed STHObjects:
o fetchall()
o fetchone()
o fetchmany()
All database results are returned in a 'table', i.e. a list of lists
(or list of dictionaries for fetchdict()).
********************************************************************************
Copyright:
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
2. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
3. This notice may not be removed from any source distribution.
Joerg Senekowitsch <senekow@ibm.net>
Notice: This code is based on mySQLmodule-0.1.4, which is
Copyright (C) 1997 Joseph Skinner <joe@earthlink.co.nz>
Copyright (C) 1997 James Henstridge <james@daa.com.au>
mySQLmodule-0.1.4 is based on mSQLmodule, which is
Portions copyright (C) 1995 Thawte Consulting, cc
Portions copyright (C) 1994 Anthony Baxter.
See the file 'Credits' for details.
Disclaimer:
THE AUTHOR MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF
THE SOFTWARE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT
EXPRESS OR IMPLIED WARRANTY. THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NON-INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE, STRICT LIABILITY OR
ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef WIN32
typedef void *HANDLE;
#include "winsock.h"
#endif
#include "Python.h"
#include "mysql.h"
static char MySQL_Version[] = "MySQLmodule-1.4: A Python interface to the MySQL database.";
typedef struct MySQL_DBH {
PyObject_HEAD
MYSQL *handle;
MYSQL connection;
int dbh_use_result;
struct MySQL_STH *sth;
} DBHObject;
typedef struct MySQL_STH {
PyObject_HEAD
MYSQL_RES *res;
#ifdef WIN32
my_ulonglong affected_rows;
my_ulonglong insert_id;
#else
int affected_rows;
int insert_id;
#endif
int sth_use_result;
struct MySQL_DBH *dbh;
} STHObject;
staticforward PyTypeObject DBH_Type;
staticforward PyTypeObject STH_Type;
static PyObject *MySQLError;
#define STHObject_Check(v) ((v)->ob_type == &STH_Type)
#define DBHObject_Check(v) ((v)->ob_type == &DBH_Type)
/*********************************************************
****** Helper routines
*********************************************************/
static int clear_channel(self)
STHObject *self;
{
if (self->res) { /* only if we have a result */
if (!mysql_eof(self->res)) {
MYSQL_ROW dummy;
while (dummy = mysql_fetch_row(self->res)) continue;
/* check for error. make sure handle exists, though */
if (self->res->handle && mysql_error(self->res->handle)[0] != 0) {
PyErr_SetString(MySQLError,mysql_error(self->res->handle));
return 1;
}
}
}
return 0;
}
/* catch empty cursors (STH) */
static int no_response(self)
STHObject *self;
{
if (self->res == NULL) {
PyErr_SetString(MySQLError,"no response body");
return 1;
}
return 0;
}
/* Take a MYSQL_ROW and turn it into a list */
static PyObject *
pythonify_row(res, thisrow)
MYSQL_RES *res;
MYSQL_ROW thisrow;
{
PyObject *rowlist, *fieldobj;
MYSQL_FIELD *tf;
int i, n;
unsigned int *lengths;
n = mysql_num_fields(res);
lengths = mysql_fetch_lengths(res);
if (lengths == NULL) {
if (res->handle && mysql_error(res->handle)[0] != 0) {
PyErr_SetString(MySQLError,mysql_error(res->handle));
} else {
PyErr_SetString(MySQLError, "pythonify_row: mysql_fetch_lengths() failed");
}
return NULL;
}
rowlist = PyList_New(n);
if (rowlist == NULL) return NULL;
mysql_field_seek(res, 0);
for (i = 0; i < n; i++) {
tf = mysql_fetch_field(res);
if (tf == NULL) {
if (res->handle && mysql_error(res->handle)[0] != 0) {
PyErr_SetString(MySQLError,mysql_error(res->handle));
} else {
PyErr_SetString(MySQLError, "pythonify_row: mysql_fetch_field() failed");
}
Py_XDECREF(rowlist);
return NULL;
}
if (thisrow[i])
switch (tf->type) {
case FIELD_TYPE_SHORT:
case FIELD_TYPE_LONG:
if (tf->flags & UNSIGNED_FLAG) {
fieldobj = PyLong_FromString(thisrow[i], (char **)NULL, 10);
} else {
fieldobj = PyInt_FromLong(atol(thisrow[i]));
}
if (fieldobj == NULL) {
Py_XDECREF(rowlist);
return NULL;
}
break;
case FIELD_TYPE_CHAR:
case FIELD_TYPE_STRING:
case FIELD_TYPE_VAR_STRING:
case FIELD_TYPE_DATE:
case FIELD_TYPE_TIME:
case FIELD_TYPE_DATETIME:
case FIELD_TYPE_TIMESTAMP:
fieldobj = PyString_FromString(thisrow[i]);
if (fieldobj == NULL) {
Py_XDECREF(rowlist);
return NULL;
}
break;
case FIELD_TYPE_TINY_BLOB:
case FIELD_TYPE_MEDIUM_BLOB:
case FIELD_TYPE_LONG_BLOB:
case FIELD_TYPE_BLOB:
fieldobj = PyString_FromStringAndSize(thisrow[i],lengths[i]);
if (fieldobj == NULL) {
Py_XDECREF(rowlist);
return NULL;
}
break;
case FIELD_TYPE_DECIMAL:
case FIELD_TYPE_DOUBLE:
case FIELD_TYPE_FLOAT:
fieldobj = PyFloat_FromDouble(atof(thisrow[i]));
if (fieldobj == NULL) {
Py_XDECREF(rowlist);
return NULL;
}
break;
default:
fieldobj = PyString_FromString(thisrow[i]);
if (fieldobj == NULL) {
Py_XDECREF(rowlist);
return NULL;
}
break;
} else {
Py_INCREF(Py_None);
fieldobj = Py_None;
}
if (PyList_SetItem(rowlist, i, fieldobj) == -1) {
Py_XDECREF(rowlist);
return NULL;
}
}
return rowlist;
}
/* Take a MYSQL_RES and turn it into a table (list of lists).
Depending on whether (res) is local (from a mysql_store_result)
or remote (from mysql_use_result) we might see client/server
errors on the mysql_fetch_row() call. If we receive a NULL
from mysql_fetch_row() we must check whether this is "no more
data" or indeed an error.
If the error was generated by pythonify_row, rowlist will be
NULL and PyErr will already be set.
*/
static PyObject *
pythonify_res(res, num)
MYSQL_RES *res;
int num;
{
PyObject *reslist;
PyObject *rowlist = NULL;
MYSQL_ROW thisrow;
int i = 0;
reslist = PyList_New(0);
if (reslist == NULL) return NULL;
while ((i != num) && (thisrow = mysql_fetch_row(res))) {
i++;
rowlist = pythonify_row(res, thisrow);
if (rowlist == NULL) goto error;
if (PyList_Append(reslist, rowlist) == -1) goto error;
Py_XDECREF(rowlist);
rowlist = NULL;
}
if (thisrow == NULL && res->handle && mysql_error(res->handle)[0] != 0) {
PyErr_SetString(MySQLError,mysql_error(res->handle));
Py_XDECREF(reslist);
return NULL;
}
return (reslist);
error:
Py_XDECREF(rowlist);
Py_XDECREF(reslist);
return NULL;
}
/* Take a MYSQL_RES and return a table of field data */
static PyObject *
pythonify_res_fields(res)
MYSQL_RES *res;
{
PyObject *reslist, *thislist;
int i, n;
char *type, flags[32];
MYSQL_FIELD *tf;
reslist = PyList_New(0);
if (reslist == NULL) return NULL;
n = mysql_num_fields(res);
for (i = 0; i < n; i++) {
tf = &(mysql_fetch_field_direct(res, i));
if (tf == NULL) {
if (res->handle && mysql_error(res->handle)[0] != 0) {
PyErr_SetString(MySQLError,mysql_error(res->handle));
} else {
PyErr_SetString(MySQLError, "pythonify_res_fields: mysql_fetch_field_direct() failed");
}
Py_XDECREF(reslist);
return NULL;
}
switch (tf->type) {
case FIELD_TYPE_SHORT:
type = "short";
break;
case FIELD_TYPE_LONG:
type = "long";
break;
case FIELD_TYPE_CHAR:
type = "char";
break;
case FIELD_TYPE_DOUBLE:
type = "double";
break;
case FIELD_TYPE_DECIMAL:
type = "decimal";
break;
case FIELD_TYPE_FLOAT:
type = "float";
break;
case FIELD_TYPE_TINY_BLOB:
type = "tiny blob";
break;
case FIELD_TYPE_MEDIUM_BLOB:
type = "medium blob";
break;
case FIELD_TYPE_LONG_BLOB:
type = "long blob";
break;
case FIELD_TYPE_BLOB:
type = "blob";
break;
case FIELD_TYPE_DATE:
type = "date";
break;
case FIELD_TYPE_TIME:
type = "time";
break;
case FIELD_TYPE_DATETIME:
type = "datetime";
break;
case FIELD_TYPE_TIMESTAMP:
type = "timestamp";
break;
case FIELD_TYPE_NULL:
case FIELD_TYPE_LONGLONG:
case FIELD_TYPE_INT24:
type = "unhandled";
break;
case FIELD_TYPE_VAR_STRING:
type = "varchar";
break;
case FIELD_TYPE_STRING:
type = "string";
break;
default:
type = "????";
break;
}
flags[0] = 0;
if (IS_PRI_KEY(tf->flags)) (void) strcpy(flags, "pri");
if (IS_NOT_NULL(tf->flags))
flags[0] ? (void) strcat(flags, " notnull") : (void) strcpy(flags, "notnull");
if ((tf->flags) & AUTO_INCREMENT_FLAG)
flags[0] ? (void) strcat(flags, " auto_inc") : (void) strcpy(flags, "auto_inc");
if ((tf->flags) & UNSIGNED_FLAG)
flags[0] ? (void) strcat(flags, " usign") : (void) strcpy(flags, "usign");
if ((tf->flags) & UNIQUE_KEY_FLAG)
flags[0] ? (void) strcat(flags, " ukey") : (void) strcpy(flags, "ukey");
if ((tf->flags) & MULTIPLE_KEY_FLAG)
flags[0] ? (void) strcat(flags, " mkey") : (void) strcpy(flags, "mkey");
thislist = Py_BuildValue("[sssis]", tf->name, tf->table, type,
tf->length, flags);
if (thislist == NULL) {
Py_XDECREF(reslist);
return NULL;
}
if (PyList_Append(reslist, thislist) == -1) {
Py_XDECREF(thislist);
Py_XDECREF(reslist);
return NULL;
}
Py_DECREF(thislist);
}
return (reslist);
}
/* concat three strings */
static void
mystrcpy(field, table, sep, name)
char *field;
char *table;
char *sep;
char *name;
{
char *s;
s = field;
while (!(*table == 0)) *s++ = *table++;
while (!(*sep == 0)) *s++ = *sep++;
while (!(*name == 0)) *s++ = *name++;
*s = 0;
}
/********************************************************
***** MySQL methods
********************************************************/
static PyObject *
MySQL_connect(self, args)
PyObject *self, *args;
{
char *dbhost = NULL;
char *dbuser = NULL;
char *dbpass = NULL;
DBHObject *DBH;
if (!PyArg_ParseTuple(args, "|sss:connect", &dbhost, &dbuser, &dbpass)) return NULL;
DBH = PyObject_NEW(DBHObject, &DBH_Type);
if (DBH == NULL) return NULL;
DBH->dbh_use_result = 0;
DBH->handle = &DBH->connection;
DBH->sth = NULL;
if (!(mysql_connect(DBH->handle, dbhost, dbuser, dbpass))) {
if (mysql_error(DBH->handle)[0] != 0) {
PyErr_SetString(MySQLError,mysql_error(DBH->handle));
} else {
/* safety. should not be reached */
PyErr_SetString(MySQLError, "connect(): could not connect to MySQL");
}
Py_XDECREF(DBH);
return NULL;
}
return ((PyObject *) DBH);
}
static PyObject *
MySQL_escape(self,args)
PyObject *self, *args;
{
char *in = NULL;
char *out = NULL;
PyObject *str;
unsigned int size, len;
if (!PyArg_ParseTuple(args, "s#:escape", &in, &size)) return NULL;
/* wonder whether one should use PyMem_* routines instead of malloc/free */
out = (char *) malloc(size*2+1);
if (!out) {
PyErr_SetString(MySQLError, "escape(): no memory");
return NULL;
}
len = mysql_escape_string(out,in,size);
str = Py_BuildValue("s#",out,len);
free(out);
return (str);
}
static struct PyMethodDef MySQL_Methods[] =
{
{"connect", MySQL_connect, METH_VARARGS},
{"escape", MySQL_escape, METH_VARARGS},
{NULL, NULL}
};
/************************************************************
****** DBH methods
************************************************************/
static PyObject *
DBH_selectdb(self, args)
DBHObject *self;
PyObject *args;
{
char *dbname;
if (!PyArg_ParseTuple(args, "s|i:selectdb", &dbname, &(self->dbh_use_result))) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if (mysql_select_db(self->handle, dbname)) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
}
Py_INCREF(Py_None);
return (Py_None);
}
static PyObject *
DBH_listdbs(self, args)
DBHObject *self;
PyObject *args;
{
MYSQL_RES *res;
PyObject *resobj;
char *wildcard = NULL;
if (!PyArg_ParseTuple(args, "|s:listdbs", &wildcard)) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if ((res = mysql_list_dbs(self->handle, wildcard)) == NULL) {
if (mysql_error(self->handle)[0] != 0) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
} else {
resobj = PyList_New(0);
return (resobj);
}
}
resobj = pythonify_res(res,-1);
mysql_free_result(res);
return (resobj);
}
static PyObject *
DBH_listtables(self, args)
DBHObject *self;
PyObject *args;
{
MYSQL_RES *res;
PyObject *resobj;
char *wildcard = NULL;
if (!PyArg_ParseTuple(args, "|s:listtables", &wildcard)) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if ((res = mysql_list_tables(self->handle, wildcard)) == NULL) {
if (mysql_error(self->handle)[0] != 0) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
} else {
resobj = PyList_New(0);
return (resobj);
}
}
resobj = pythonify_res(res,-1);
mysql_free_result(res);
return (resobj);
}
static PyObject *
DBH_listfields(self, args)
DBHObject *self;
PyObject *args;
{
char *tname;
char *wildcard = NULL;
MYSQL_RES *res;
PyObject *resobj;
if (!PyArg_ParseTuple(args, "s|s:listfields", &tname, &wildcard)) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if ((res = mysql_list_fields(self->handle, tname, wildcard)) == NULL) {
if (mysql_error(self->handle)[0] != 0) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
} else {
resobj = PyList_New(0);
return (resobj);
}
}
resobj = pythonify_res_fields(res);
mysql_free_result(res);
return (resobj);
}
static PyObject *
DBH_listprocesses(self, args)
DBHObject *self;
PyObject *args;
{
MYSQL_RES *res;
PyObject *resobj;
if (!PyArg_ParseTuple(args, ":listprocesses")) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if ((res = mysql_list_processes(self->handle)) == NULL) {
if (mysql_error(self->handle)[0] != 0) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
} else {
resobj = PyList_New(0);
return (resobj);
}
}
resobj = pythonify_res(res,-1);
mysql_free_result(res);
return (resobj);
}
static PyObject *
DBH_query_helper(self, query, size)
DBHObject *self;
char *query;
unsigned int size;
{
MYSQL_RES *res;
PyObject *resobj;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if (mysql_real_query(self->handle, query, size)) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
}
if (self->dbh_use_result) {
res = mysql_use_result(self->handle);
} else {
res = mysql_store_result(self->handle);
}
if (mysql_error(self->handle)[0] != 0) {
PyErr_SetString(MySQLError,mysql_error(self->handle));
if (res) mysql_free_result(res);
return NULL;
}
if (res == NULL) { /* query did not return a result, return affected_rows */
return (PyInt_FromLong((long) mysql_affected_rows(self->handle)));
}
resobj = pythonify_res(res,-1);
mysql_free_result(res);
return (resobj);
}
static PyObject *
DBH_do(self, args)
DBHObject *self;
PyObject *args;
{
char *query;
unsigned int size;
if (!PyArg_ParseTuple(args, "s#:do", &query, &size)) return NULL;
return DBH_query_helper(self, query, size);
}
static PyObject *
DBH_create(self, args)
DBHObject *self;
PyObject *args;
{
char *dbname;
if (!PyArg_ParseTuple(args, "s:create", &dbname)) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if (mysql_create_db(self->handle, dbname)) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
}
Py_INCREF(Py_None);
return (Py_None);
}
static PyObject *
DBH_close(self, args)
DBHObject *self;
PyObject *args;
{
if (!PyArg_ParseTuple(args, ":close")) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
mysql_close(self->handle); /* unconditional */
Py_INCREF(Py_None);
return (Py_None);
}
static PyObject *
DBH_insertid(self, args)
DBHObject *self;
PyObject *args;
{
if (!PyArg_ParseTuple(args, ":insertid")) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
return (PyInt_FromLong((long) mysql_insert_id(self->handle)));
}
static PyObject *
DBH_stat(self, args)
DBHObject *self;
PyObject *args;
{
char *stat;
if (!PyArg_ParseTuple(args, ":stat")) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if ((stat = mysql_stat(self->handle)) == NULL) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
}
return (PyString_FromString(stat));
}
static PyObject *
DBH_clientinfo(self, args)
DBHObject *self;
PyObject *args;
{
char *info;
if (!PyArg_ParseTuple(args, ":clientinfo")) return NULL;
/* MySQL returns the server version on this call :-(
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if ((info = mysql_get_client_info()) == NULL) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
}
*/
return (PyString_FromString(MySQL_Version));
}
static PyObject *
DBH_hostinfo(self, args)
DBHObject *self;
PyObject *args;
{
char *info;
if (!PyArg_ParseTuple(args, ":hostinfo")) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if ((info = mysql_get_host_info(self->handle)) == NULL) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
}
return (PyString_FromString(info));
}
static PyObject *
DBH_serverinfo(self, args)
DBHObject *self;
PyObject *args;
{
char *info;
if (!PyArg_ParseTuple(args, ":serverinfo")) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if ((info = mysql_get_server_info(self->handle)) == NULL) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
}
return (PyString_FromString(info));
}
static PyObject *
DBH_protoinfo(self, args)
DBHObject *self;
PyObject *args;
{
int info;
if (!PyArg_ParseTuple(args, ":protoinfo")) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if (!(info = mysql_get_proto_info(self->handle))) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
}
return (PyInt_FromLong((long) info));
}
static PyObject *
DBH_drop(self, args)
DBHObject *self;
PyObject *args;
{
char *dbname;
if (!PyArg_ParseTuple(args, "s:drop", &dbname)) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if (mysql_drop_db(self->handle, dbname)) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
}
Py_INCREF(Py_None);
return (Py_None);
}
static PyObject *
DBH_reload(self, args)
DBHObject *self;
PyObject *args;
{
if (!PyArg_ParseTuple(args, ":reload")) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if (mysql_reload(self->handle)) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
}
Py_INCREF(Py_None);
return (Py_None);
}
static PyObject *
DBH_shutdown(self, args)
DBHObject *self;
PyObject *args;
{
if (!PyArg_ParseTuple(args, ":shutdown")) return NULL;
if (self->sth && clear_channel(self->sth)) return NULL;
Py_XDECREF(self->sth);
self->sth = NULL;
if (mysql_shutdown(self->handle)) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
return NULL;
}
Py_INCREF(Py_None);
return (Py_None);
}
/* return a cursor object (STH) for the given query */
static PyObject *
DBH_query(self, args)
DBHObject *self;
PyObject *args;
{
STHObject *sth;
char *query;
unsigned int size;
sth = PyObject_NEW(STHObject, &STH_Type);
if (sth == NULL) return NULL;
sth->sth_use_result = self->dbh_use_result;
sth->dbh = NULL;
sth->res = NULL;
if (!PyArg_ParseTuple(args, "s#|i:query", &query, &size, &(sth->sth_use_result))) {
Py_XDECREF(sth);
return NULL;
}
if (self->sth && clear_channel(self->sth)) {
Py_XDECREF(sth);
return NULL;
}
Py_XDECREF(self->sth);
self->sth = NULL;
if (mysql_real_query(self->handle, query, size)) {
PyErr_SetString(MySQLError, mysql_error(self->handle));
Py_XDECREF(sth);
return NULL;
}
if (sth->sth_use_result) {
sth->res = mysql_use_result(self->handle);
if (mysql_error(self->handle)[0] != 0) {
PyErr_SetString(MySQLError,mysql_error(self->handle));
Py_XDECREF(sth);
return NULL;
}
sth->dbh = self;
Py_XINCREF(self);
self->sth = sth;
Py_XINCREF(sth);
} else {
sth->res = mysql_store_result(self->handle);
if (mysql_error(self->handle)[0] != 0) {
PyErr_SetString(MySQLError,mysql_error(self->handle));
Py_XDECREF(sth);
return NULL;
}
}
sth->affected_rows = mysql_affected_rows(self->handle);
sth->insert_id = mysql_insert_id(self->handle);
return (PyObject *) sth;
}
/* For DBH['query'] syntax */
static PyObject *
DBH_subscript(self, subs)
PyObject *self, *subs;
{
char *query;
unsigned int size;
if (!PyArg_Parse(subs, "s#:subscript", &query, &size)) {
PyErr_SetString(MySQLError, "subscript expects a query string");
return NULL;
}
return DBH_query_helper(self, query, size);
}
static int
DBH_subscript_assign(self, subs, val)
PyObject *self, *subs, *val;
{
PyErr_SetString(MySQLError, "MySQL handle is readonly");
return -1; /* -1 is error code in interpreter main loop! (ceval.c) */
}
static int
DBH_len(self, subs)
PyObject *self, *subs;
{
PyErr_SetString(MySQLError, "len() of unsized object");
return -1;
}
static struct PyMethodDef DBH_methods[] =
{
{"selectdb", (PyCFunction) DBH_selectdb, METH_VARARGS},
{"do", (PyCFunction) DBH_do, METH_VARARGS},
{"query", (PyCFunction) DBH_query, METH_VARARGS},
{"listdbs", (PyCFunction) DBH_listdbs, METH_VARARGS},
{"listtables", (PyCFunction) DBH_listtables, METH_VARARGS},
{"listfields", (PyCFunction) DBH_listfields, METH_VARARGS},
{"listprocesses", (PyCFunction) DBH_listprocesses, METH_VARARGS},
{"create", (PyCFunction) DBH_create, METH_VARARGS},
{"stat", (PyCFunction) DBH_stat, METH_VARARGS},
{"clientinfo", (PyCFunction) DBH_clientinfo, METH_VARARGS},
{"hostinfo", (PyCFunction) DBH_hostinfo, METH_VARARGS},
{"serverinfo", (PyCFunction) DBH_serverinfo, METH_VARARGS},
{"protoinfo", (PyCFunction) DBH_protoinfo, METH_VARARGS},
{"drop", (PyCFunction) DBH_drop, METH_VARARGS},
{"reload", (PyCFunction) DBH_reload, METH_VARARGS},
{"insert_id", (PyCFunction) DBH_insertid, METH_VARARGS},
{"close", (PyCFunction) DBH_close, METH_VARARGS},
{"shutdown", (PyCFunction) DBH_shutdown, METH_VARARGS},
{NULL, NULL} /* sentinel */
};
static PyMappingMethods mysql_as_mapping =
{
(inquiry) DBH_len, /*length */
(binaryfunc) DBH_subscript, /*subscript */
(objobjargproc) DBH_subscript_assign, /*assign subscript */
};
static PyObject *
DBH_getattr(self, name)
DBHObject *self;
char *name;
{
return Py_FindMethod(DBH_methods, (PyObject *) self, name);
}
static void
DBH_dealloc(self)
register DBHObject *self;
{
mysql_close(self->handle);
PyMem_DEL(self);
}
static PyTypeObject DBH_Type =
{
PyObject_HEAD_INIT(NULL)
0,
"DBHObject",
sizeof(DBHObject),
0,
(destructor) DBH_dealloc, /*tp_dealloc */
0, /*tp_print */
(getattrfunc) DBH_getattr, /*tp_getattr */
0, /*tp_setattr */
0, /*tp_compare */
0, /*tp_repr */
0, /*tp_as_number */
0, /*tp_as_sequence */
&mysql_as_mapping, /*tp_as_mapping */
};
/*************************************************************
**** STH methods
**************************************************************/
static PyObject *
STH_fields(self, args)
STHObject *self;
PyObject *args;
{
PyObject *resobj;
if ((!PyArg_ParseTuple(args, ":fields")) || no_response(self)) return NULL;
resobj = pythonify_res_fields(self->res);
if (resobj == NULL) {
mysql_free_result(self->res);
self->res = NULL;
}
return (resobj);
}
static PyObject *
STH_fetchrows(self, args)
STHObject *self;
PyObject *args;
{
PyObject *resobj;
int i = -1;
if ((!PyArg_ParseTuple(args, "|i:fetchrows", &i)) || no_response(self)) return NULL;
if (i < 0 && self->sth_use_result == 0) mysql_data_seek(self->res,0);
resobj = pythonify_res(self->res, i);
if (resobj == NULL) {
mysql_free_result(self->res);
self->res = NULL;
}
return (resobj);
}
static PyObject *
STH_fetchdict(self,args)
STHObject *self;
PyObject *args;
{
int i = -1;
int tlen = 0;
int j, flen, rows, cols;
char *fieldname = NULL;
PyObject *rowdict = NULL;
PyObject *datalist, *rowlist, *value;
MYSQL_FIELD *tf;
if ((!PyArg_ParseTuple(args, "|i:fetchdict", &i)) || no_response(self)) return NULL;
if (i < 0 && self->sth_use_result == 0) mysql_data_seek(self->res,0);
datalist = pythonify_res(self->res,i);
if (datalist == NULL) {
mysql_free_result(self->res);
self->res = NULL;
return NULL;
}
rows = PyList_Size(datalist);
if (rows > 0) {
cols = mysql_num_fields(self->res);
for (j=0; j<cols; j++) {
tf = &(mysql_fetch_field_direct(self->res,j));
if (tf == NULL) {
if (self->res->handle && mysql_error(self->res->handle)[0] != 0) {
PyErr_SetString(MySQLError,mysql_error(self->res->handle));
} else {
PyErr_SetString(MySQLError, "fetchdict: mysql_fetch_field_direct() failed");
}
goto error;
}
flen = strlen(tf->table) + strlen(tf->name);
tlen = flen > tlen ? flen : tlen;
}
if ((fieldname = (char *) malloc(tlen+2)) == NULL) {
PyErr_SetString(MySQLError,"fetchdict(): no memory (fieldname)");
goto error;
}
for (i=0; i<rows; i++) {
rowdict = PyDict_New();
if (rowdict == NULL) goto error;
rowlist = PyList_GetItem(datalist,i);
if (rowlist == NULL) goto error;
for (j=0; j<cols; j++) {
tf = &(mysql_fetch_field_direct(self->res,j));
if (tf == NULL) {
if (self->res->handle && mysql_error(self->res->handle)[0] != 0) {
PyErr_SetString(MySQLError,mysql_error(self->res->handle));
} else {
PyErr_SetString(MySQLError,"fetchdict(): mysql_fetch_field_direct() failed");
}
goto error;
}
mystrcpy(fieldname,tf->table,".",tf->name);
value = PyList_GetItem(rowlist,j);
if (value == NULL) goto error;
if (PyDict_SetItemString(rowdict,fieldname,value)) goto error;
}
if (PyList_SetItem(datalist,i,rowdict)) goto error;
}
free(fieldname);
}
return (datalist);
error:
Py_XDECREF(datalist);
Py_XDECREF(rowdict);
if (fieldname) free(fieldname);
return NULL;
}
static PyObject *
STH_seek(self, args)
STHObject *self;
PyObject *args;
{
unsigned int i;
if ((!PyArg_ParseTuple(args, "i:seek", &i)) || no_response(self)) return NULL;
if (self->sth_use_result) {
PyErr_SetString(MySQLError, "STH_seek: cannot seek on server");
return NULL;
}
mysql_data_seek(self->res, i);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
STH_numrows(self, args)
STHObject *self;
PyObject *args;
{
if ((!PyArg_ParseTuple(args, ":numrows")) || no_response(self)) return NULL;
return PyInt_FromLong((long) mysql_num_rows(self->res));
}
static PyObject *
STH_numfields(self, args)
STHObject *self;
PyObject *args;
{
if ((!PyArg_ParseTuple(args, ":numfields")) || no_response(self)) return NULL;
return PyInt_FromLong((long) mysql_num_fields(self->res));
}
static PyObject *
STH_eof(self, args)
STHObject *self;
PyObject *args;
{
if ((!PyArg_ParseTuple(args, ":eof")) || no_response(self)) return NULL;
if (mysql_eof(self->res)) { /* only useful if mysql_use_result() has been used */
Py_INCREF(Py_True);
return Py_True;
} else {
Py_INCREF(Py_False);
return Py_False;
}
}
static PyObject *
STH_affectedrows(self, args)
STHObject *self;
PyObject *args;
{
if (!PyArg_ParseTuple(args, ":affectedrows")) return NULL;
return PyInt_FromLong((long) self->affected_rows);
}
static PyObject *
STH_insertid(self, args)
STHObject *self;
PyObject *args;
{
if (!PyArg_ParseTuple(args, ":insertid")) return NULL;
return PyInt_FromLong((long) self->insert_id);
}
static struct PyMethodDef STH_methods[] =
{
{"fields", (PyCFunction) STH_fields, METH_VARARGS},
{"fetchrows", (PyCFunction) STH_fetchrows, METH_VARARGS},
{"fetchdict", (PyCFunction) STH_fetchdict, METH_VARARGS},
{"seek", (PyCFunction) STH_seek, METH_VARARGS},
{"numrows", (PyCFunction) STH_numrows, METH_VARARGS},
{"numfields", (PyCFunction) STH_numfields, METH_VARARGS},
{"eof", (PyCFunction) STH_eof, METH_VARARGS},
{"affectedrows", (PyCFunction) STH_affectedrows, METH_VARARGS},
{"insert_id", (PyCFunction) STH_insertid, METH_VARARGS},
{NULL, NULL}
};
static PyObject *
STH_getattr(self, name)
STHObject *self;
char *name;
{
return Py_FindMethod(STH_methods, (PyObject *) self, name);
}
static void
STH_dealloc(self)
register STHObject *self;
{
if (self->res) mysql_free_result(self->res);
Py_XDECREF(self->dbh);
PyMem_DEL(self);
}
static PyTypeObject STH_Type =
{
PyObject_HEAD_INIT(NULL)
0,
"STHObject",
sizeof(STHObject),
0,
(destructor) STH_dealloc, /*tp_dealloc */
0, /*tp_print */
(getattrfunc) STH_getattr, /*tp_getattr */
0, /*tp_setattr */
0, /*tp_compare */
0, /*tp_repr */
0, /*tp_as_number */
0, /*tp_as_sequence */
0, /*tp_as_mapping */
};
/***********************************************************
******** Module initialization
***********************************************************/
void
initMySQL()
{
PyObject *module, *dict, *str;
DBH_Type.ob_type = &PyType_Type;
STH_Type.ob_type = &PyType_Type;
module = Py_InitModule("MySQL", MySQL_Methods);
dict = PyModule_GetDict(module);
if (PyDict_SetItemString(dict, "DBH_Type", (PyObject *) & DBH_Type) != 0)
Py_FatalError("Cannot add to MySQL dictionary");
if (PyDict_SetItemString(dict, "STH_Type", (PyObject *) & STH_Type) != 0)
Py_FatalError("Cannot add to MySQL dictionary");
str = PyString_FromString(MySQL_Version);
if (PyDict_SetItemString(dict, "__doc__", str) != 0)
Py_FatalError("Cannot add to MySQL dictionary");
Py_XDECREF(str);
MySQLError = PyErr_NewException("MySQL.error",NULL,NULL);
if (PyDict_SetItemString(dict, "error", MySQLError) != 0)
Py_FatalError("Cannot add to MySQL dictionary");
}
./MySQLmodule-1.4/README 100664 765 765 37400 6605362313 12525 0 ustar www www The following is the documentation for MySQLmodule-1.4.
This module has been developed under Linux (RH50),
MySQL 3.21.30, and Python 1.5.1.
For copyright notices see MySQLmodule.c.
MySQLmodule-1.x is based on mySQLmodule-0.1.4 by
Copyright (C) 1997 Joseph Skinner <joe@earthlink.co.nz>
Copyright (C) 1997 James Henstridge <james@daa.com.au>
mySQLmodule-0.1.4 is based on mSQLmodule, which is
Portions copyright (C) 1995 Thawte Consulting, cc
Portions copyright (C) 1994 Anthony Baxter.
See 'Credits' for details.
Joerg Senekowitsch (senekow@ibm.net), October 1998
-----------------------------------------------------------------------------
**CONTENTS**
0. Why another Python/MySQL interface
1. Compiling and installing the MySQL module
2. Exported types, functions and classes
3. Using the MySQL module
4. Notes on server side storage
5. Acknowledgements
**WHY ANOTHER PYTHON/MYSQL INTERFACE**
I recently came across a problem storing strings containing ASCII zero (\0)
in the MySQL database. After first blaming Python (which threw the original
error), I checked the mySQLmodule code and ran across a bunch of problems.
Some routines would not free allocated storage, some MySQL API functions
were not available, and I disliked the fact that mySQLmodule would return
different data structures depending on the method (and tuples at that!).
So I ripped the code apart, left the framework, but made lots of changes.
Because the changes include a change in (Python) methods and return
values, I upped the major version number and changed the name of the
module to MySQL, so that it would not clash with the original mySQL.
Rational for the change to return "list of lists" instead of
"tuple" or "list of tuple". I don't want my own DB access routines
to worry about the return type and I want to be able to modify the
data in the returned table.
Data = DBH['select * from MyTable']
if Data:
rows = len(Data)
cols = len(Data[0])
for i in range(rows):
for j in range(cols):
if not Data[i][j]: Data[i][j] = DefaultElement()
Do_Something(Data)
No need to complicate that by having tuples inside the outer list.
For those who prefer dictionaries, the STH method fetchdict()
will return a list of dictionaries. The dictionary keys are
qualified with the corresponding table name(s).
**COMPILING AND INSTALLING**
i. See README.NT if you are installing on a WIN32 system.
ii. Copy MySQLmodule.c into your Modules subdirectory of the Python
source distribution.
iii. Add the following line to your Setup file in that directory:
MySQL MySQLmodule.c -L/usr/local/lib/mysql/ -lmysqlclient \
-I/usr/local/include/mysql
Note that the location of the MySQL library and the include
directory may be different on your particular system. You may
build the module shared (insert below the *shared* indicator
in the Setup file).
iv. If you have built Python before, simply run make in your
main Python directory. If not, follow the instructions on
how to compile/install Python.
To build a dynamically loadable module without access to the python
source tree, use (Trond Eivind Glomsrød):
gcc -shared -I/usr/include/python1.5 -I/usr/local/include/mysql \
MySQLmodule.c -lmysqlclient -L/usr/lib/python1.5/config -lpython1.5 \
-o MySQLmodule.so
and move the resulting MySQLmodule.so file into the PYTHONPATH. Again,
substitute the proper locations of your include and library files.
Note that the module is case sensitive, and that the name has been changed
to MySQL *deliberately* so as not to break any existing code that uses
the old mySQL module.
**EXPORTED TYPES AND OBJECTS**
The module (MySQL) exports the following:
DBH_Type: the type of the database object
STH_Type: the type of the cursor object
error: an exception raised in certain circumstances (rather than TypeError)
__doc__: the version accessible from Python
connect([host[,user[,pass]]])
a function returning a database object. The optional arguments
are the name of the host to connect to, the username for authenticating
to MySQL, and the associated password. If no host is given, the function
will assume 'localhost' (and use a fast Unix socket for the connection)
escape(string)
will (hopefully) return a string properly escaped to allow insertion
into the DB. This routine calls mysql_escape_string(), which is broken
in 3.21.29-gamma. Versions >=3.21.30 seem to work correctly.
MySQL.connect() returns a database handle (DBH) with the following methods:
(Note: in the following, 'Table' means 'list of lists' (except fetchdict))
Table = DBH.listdbs([wild])
returns a table giving the names of the databases on the
MySQL host to which one has connected with MySQL.connect(). The optional
argument is a MySQL wildcard string (same syntax as LIKE).
DBH.selectdb(DB_Name[,storage])
attaches this object to a particular database. Queries executed
will be directed to that database until another selectdb method
call is made. The optional integer 'storage' can be used to keep
query result sets on the server. Note that this negatively impacts
the server performance, but allows clients with smaller memory
footprints, since records are only transferred upon request.
The default is 0, i.e. all records are transferred to the client.
Table = DBH.listtables([wild])
return a table with table names in the selected
database. Only valid after a selectdb call has been made.
The optional argument can be used to restrict the returned set of
tables (same syntax as LIKE).
Table = DBH.listfields(table[,wild])
return a table of the description(s) of the fields in the given table.
The optional argument can be used to restrict the returned set
of fields (same syntax as LIKE).
Table = DBH.listprocesses()
returns information about the running MySQL processes. Requires
privileges (otherwise returns None).
String = DBH.stat()
returns status information from MySQL.
DBH.create(DB_Definition)
creates a new database.
DBH.drop(DB_Name)
could ruin your day.
DBH.reload()
reload MySQL privilege tables.
DBH.shutdown()
takes down the MySQL daemon.
DBH.close()
closes a DB connection.
String = DBH.clientinfo()
returns MySQLmodule version information.
String = DBH.serverinfo()
returns MySQL server information.
String = DBH.hostinfo()
returns information about the connecting host and connection type.
Integer = DBH.protoinfo()
returns the MySQL protocol version number (10).
Table = DBH.do(query) or Table = DBH[query]
return the result of the SQL query. Returns the result of the
query or the number of affected rows (mySQL may lie about that).
Both methods use the storage type established with DBH.selectdb().
See code comments if you're running a WIN32 version.
Integer = DBH.insert_id()
access to the last generated auto_increment number. This number
can change if queries have been submitted between calls.
See code comments if you're running a WIN32 version.
STH = DBH.query(query[,storage])
returns a statement handle for cursor methods (see below).
The optional 'storage' parameter can be used to override
the DBH default established with DBH.selectdb().
Methods for statement handles (STH):
Table = STH.fetchrows([n])
return the results of the DB query. If n < 0, all rows will be fetched.
Otherwise, only the next n rows will be returned. The default is to
return all rows.
Table = STH.fetchdict([n])
same as STH.fetchrows(), except that a list of dictionaries is returned
with 'tablename.fieldname:data' pairs.
Table = STH.fields()
return field descriptions of the result of the STH query. Currently
MySQLmodule knows about "pri", "notnull", "auto_inc", "ukey", and "mkey".
STH.seek(n)
move cursor to row n (0 is the first row).
Only available if client side result storage (=0, see DBH.selectdb)
has been selected. Otherwise, will throw an exception.
Integer = STH.numrows()
returns how many rows are in the result of the STH query.
Warning: in reality this number reflects how many records the
*client* has received. For server side storage methods this
number starts out at 0 and increases as the client fetches the
rows. For client side storage, this number immediately gives
the total number of rows for this query.
Integer = STH.numfields()
returns how many columns are in the result of the STH query.
Integer = STH.affectedrows()
returns how many rows have been affected by the last query.
Note that MySQL lies about this number in certain cases.
See code comments if you're running a WIN32 version.
Integer = STH.insert_id()
return the auto_increment value from an insert STH query.
Note that this number is persistent as long as the STH exists.
See code comments if you're running a WIN32 version.
Integer = STH.eof()
returns 1 if the last row has been read, otherwise 0.
Always 1 if client side storage has been selected (default),
and only marginally useful for server side storage, since
the flag will change to true only _after_ an attempt has
been made to read past the last record.
**USING THE MySQL MODULE**
import MySQL
DBH = MySQL.connect() # localhost
print DBH.listdbs()
DBH.selectdb('test')
print DBH.serverinfo()
print DBH.stat()
DBH["create table pytest (x int, y int, s char(20))"]
DBH["insert into pytest values (1,2,'abc')"]
DBH.do("insert into pytest values (3,4,'def')")
STH = DBH.query("insert into pytest values (5,6,'ghi')")
print STH.affectedrows()
print DBH['select * from pytest']
STH = DBH.query("select * from pytest")
print STH.numrows()
print STH.fields()
print STH.fetchrows(-1)
STH.seek(0)
print STH.fetchrows(1)
print STH.fetchrows(1)
STH.seek(0)
print STH.fetchrows(2)
print STH.fetchrows(2)
print STH.numfields()
STH.seek(0)
print STH.fetchdict(1)
print STH.fetchdict()
STH = DBH.query("select * from pytest",1)
print STH.fetchdict(1)
print STH.fetchdict() # compare to previous dicts
STH = DBH.query("select * from pytest",1)
print STH.fetchrows(1)
print STH.eof()
print STH.fetchrows()
print STH.eof()
DBH['drop table pytest']
**NOTES ON SERVER SIDE STORAGE**
MySQL offers two slightly different ways of accessing database data.
The default method in MySQLmodule is to use client side storage, i.e.
all queries, including the cursor (STH) methods fetch all data from the
server. Rows are accessed through STH.fetchrows(n) or STH.fetchdict(n)
individually (n=1), chunked (n>1), all at once (n<0), or, for the
wiseguys, none at all (n=0). STH.numrows() can tell *up front*, i.e.
right after the query has been made, how many rows are in the result.
STH.seek(k) can be used to access rows randomly. The drawback of client
side storage is that it uses (client) memory to hold all the rows.
Client side storage allows for constructs such as:
STH = DBH.query("select * from Foo")
N = STH.numrows()
if N > 1000: raise Hell,"You must be joking!"
for i in xrange(N):
[Data] = STH.fetchdict(1)
Since the client has effectively transferred all rows, as far as the
server is concerned all transactions on this channel have ceased
and the server is ready to accept new commands. It also means that
STH.eof() is always true (1) for client side storage.
Server side storage does not require that much client memory since
all records are transferred on a request basis. However, server side
storage has several drawbacks. Since now the possibility arises that
a client did not retrieve all rows, each new command must check whether
the server is ready to accept a new command. If not, the command must
clear the command channel by issuing enough reads to retrieve the
remaining rows. The (3.21) MySQL API does not offer some kind of "abort()"
command. STH.numrows() no longer knows about how many rows were
selected by the query, so the above example code would fail.
STH.numrows() will, however, be updated as rows are read, e.g.:
STH = DBH.query("select * from Foo")
Data = STH.fetchrows(-1)
print "Got",STH.numrows(),"rows." # len(Data) is the same
STH.eof() only makes sense with server side storage, but even here
it is not all that useful:
STH = DBH.query("select 1")
print STH.eof() # will print 0
Data = STH.fetchrows(1) # retrieve the row
print STH.eof() # still 0 :-(
Data = STH.fetchrows(1) # must repeat. Data will be []
print STH.eof() # now we get 1, but we already
# knew that we've hit the end
One might consider this a bug. STH.seek(k) is no longer available and
will throw an error ("cannot seek on server"), i.e. rows must now be
read sequentially.
Server side storage also puts more strain on the server. In particular,
the server needs to remain in contact with the client until all rows
have been read. According to the MySQL manual clients are advised to
speedily retrieve the rows and not do any lengthy processing or, worse,
allow the user to stop the retrieval (e.g. by pressing Ctrl-S in an
interactive interface).
For those who cannot decide which method is more suitable for their
application, MySQLmodule allows to mix both methods freely. The default
behavior can be set with DBH.selectdb() and can be changed for individual
cursor (STH) based queries. Note that incomplete server side queries
will be cancelled by newly issued commands:
STH = DBH.query("select * from Foo",1) # use server side storage
Tables = DBH.listtables() # stomp on previous results
Data = STH.fetchrows() # nothing here anymore
vs.
STH = DBH.query("select * from Foo",0) # use client side storage
Tables = DBH.listtables() # won't interfere
Data = STH.fetchrows() # no problem...
Server side storage also makes for brain warping code in MySQLmodule.
Normally (with client side storage) STH cursors are independent of
the database handle. Immediately after the query all data is transferred
and the user is free to do whatever she likes with the DBH or STH handles.
With server side storage this becomes tricky. The memory chunk need for
the database connection is provided by the DBH handle. With server side
cursors, a pointer to this handle is stored in the STH handle. MySQLmodule
makes sure that this memory chunk is not deallocated before all outstanding
(server side) cursors are closed. This means that mysql_close() is not
necessarily called if the database handle DBH is destroyed:
DBH = MySQL.connect() # get a DB handle
STH = DBH.query("select 1",1) # server side cursor
del DBH # mysql_close() *not* called
STH.fetchrows() # will succeed!
del STH # now mysql_close() will be called
# in DBH_dealloc()
If you need to close the DB handle immediately, use DBH-close(). All further
attempts to communicate on this handle (even outstanding server side cursors)
will then receive a "... server has gone away" exception. Since mySQL
cannot accept commands out of sequence, all DBH methods must check
for incomplete STH cursors. To access those the DBH handle contains a
pointer to the STH cursor...sigh.
**ACKNOWLEDGEMENTS**
Thanks to the guys who developed Python (Guido et al.).
Python is a wonderful language.
Thanks to Monty Widenius and TcX Datakonsult AB for MySQL, which beat out
mSQL, Oracle, Solid, and Postgres for my application.
Thanks to the individuals who contributed to the development
of the Python/MySQL interface:
Joseph Skinner
James Henstridge
Thawte Consulting
Anthony Baxter
Please see the file 'Credits' for the original mySQLmodule
copyright statements.
./MySQLmodule-1.4/README.NT 100664 765 765 2005 6605365537 13031 0 ustar www www Installing MySQLmodule-1.4 on WindowsNT.
----------------------------------------
The following instructions are based on information provided by
Nigel Head (nhead@houbits.com).
i. You'll need to get hold of libMySQL.dll from the win32-mysql
clients package at version 3.22.8 or higher; earlier versions
won't cut it. This is available at www.tcx.se (or its mirrors)
for free download. You should probably move the file into the
same location as your python15.dll.
ii. Compile MySQLmodule-1.4 with the switch WIN32 enabled.
VC5 workspace and project files MySQL.dsp and MySQL.dsw are
included (but may have to be modified to suit your environment).
iii. Move the resulting MySQL.pyd file into your Python DLL directory.
Note: I don't use NT, nor do I have (or want) access to one of
these beasts. If this blows up on you, you're totally on
your own. You best chances for help are probably to send
a message to comp.lang.python.
Joerg Senekowitsch, October 1998
./MySQLmodule-1.4/MySQL.dsp 100664 765 765 7716 6605363563 13321 0 ustar www www # Microsoft Developer Studio Project File - Name="MySQL" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 5.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=MySQL - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "MySQL.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "MySQL.mak" CFG="MySQL - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "MySQL - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "MySQL - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "MySQL - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\Include" /I "..\..\PC" /I "d:\mysql\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "__WIN32__" /D "WIN32" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 ..\Release\python15.lib d:\mysql\lib\opt\libmysql.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/MySQL.pyd"
!ELSEIF "$(CFG)" == "MySQL - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\..\Include" /I "..\..\PC" /I "d:\mysql\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "__WIN32__" /D "WIN32" /YX /FD /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 ..\Debug\python15.lib d:\mysql\lib\debug\libmysql.lib wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Debug/MySQL.pyd" /pdbtype:sept /export:initMySQL
# SUBTRACT LINK32 /pdb:none
!ENDIF
# Begin Target
# Name "MySQL - Win32 Release"
# Name "MySQL - Win32 Debug"
# Begin Source File
SOURCE=.\MySQLmodule.c
# End Source File
# End Target
# End Project
./MySQLmodule-1.4/MySQL.dsw 100664 765 765 1027 6605363563 13315 0 ustar www www Microsoft Developer Studio Workspace File, Format Version 5.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "MySQL"=".\MySQL.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################