pkg://MySQLmodule-1.1.tar.gz:15210/
MySQLmodule-1.1/MySQLmodule.c
downloads
/*
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.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.
*/
#include "Python.h"
#include <sys/types.h>
#include <sys/stat.h>
#include "mysql.h"
char MySQL_Version[] = "MySQL-Python-1.1";
static PyObject *pythonify_res();
static PyObject *pythonify_res_fields();
typedef struct {
PyObject_HEAD
MYSQL handle;
int valid;
int dbh_use_result;
MYSQL_RES *cursor;
} DBHObject;
typedef struct {
PyObject_HEAD
MYSQL_RES *res;
ulong affected_rows;
ulong insert_id;
int sth_use_result;
} STHObject;
staticforward PyTypeObject MySQLType;
staticforward PyTypeObject ResType;
static PyObject *MySQLError;
static PyObject *STH(MYSQL_RES *, MYSQL, int);
/*********************************************************
****** Helper routines
*********************************************************/
static void clear_channel(self)
DBHObject *self;
{
if (self->cursor) {
/* Note that eof() will signal too late */
if (!mysql_eof(self->cursor)) {
/* MySQL doesn't have any abort() method :-( */
MYSQL_ROW dummy;
while (dummy = mysql_fetch_row(self->cursor)) continue;
}
self->cursor = NULL;
}
}
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;
uint *lengths;
n = mysql_num_fields(res);
lengths = mysql_fetch_lengths(res);
if (lengths == NULL) {
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) {
PyErr_SetString(MySQLError, "pythonify_row: mysql_fetch_field() failed");
Py_DECREF(rowlist);
return NULL;
}
if (thisrow[i])
switch (tf->type) {
case FIELD_TYPE_SHORT:
case FIELD_TYPE_LONG:
fieldobj = PyInt_FromLong(atol(thisrow[i]));
if (fieldobj == NULL)
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)
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)
return NULL;
break;
case FIELD_TYPE_DECIMAL:
case FIELD_TYPE_DOUBLE:
case FIELD_TYPE_FLOAT:
fieldobj = PyFloat_FromDouble(atof(thisrow[i]));
if (fieldobj == NULL)
return NULL;
break;
default:
fieldobj = PyString_FromString(thisrow[i]);
if (fieldobj == NULL)
return NULL;
break;
} else {
Py_INCREF(Py_None);
fieldobj = Py_None;
}
if (PyList_SetItem(rowlist, i, fieldobj) == -1)
return NULL;
}
return rowlist;
}
/* Take a MYSQL_RES and turn it into a table (list of lists). */
static PyObject *
pythonify_res(res, num)
MYSQL_RES *res;
int num;
{
PyObject *reslist, *rowlist;
MYSQL_ROW thisrow;
int i = 0;
reslist = PyList_New(0);
if (reslist == NULL)
return NULL;
/* thisrow == NULL if no more rows or if error. How to distinguish? */
while ((i != num) && (thisrow = mysql_fetch_row(res))) {
i++;
rowlist = pythonify_row(res, thisrow);
if (rowlist == NULL)
return NULL;
if (PyList_Append(reslist, rowlist) == -1)
return NULL;
Py_DECREF(rowlist);
}
return (reslist);
}
/* 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[14];
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) {
PyErr_SetString(MySQLError, "pythonify_res_fields: mysql_fetch_field_direct() failed");
Py_DECREF(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;
}
if (IS_PRI_KEY(tf->flags))
strcpy(flags, "pri");
else
flags[0] = 0;
if (IS_NOT_NULL(tf->flags))
if (flags[0])
strcat(flags, " notnull");
else
strcpy(flags, "notnull");
else
flags[0] = 0;
thislist = Py_BuildValue("[sssis]", tf->name, tf->table, type, tf->length,
flags);
if (thislist == NULL)
return NULL;
if (PyList_Append(reslist, thislist) == -1)
return NULL;
Py_DECREF(thislist);
}
return (reslist);
}
/* mysql_escape_string() seems broken (as of 3.21.29-gamma) */
static uint
escape_chars(out, in, size)
char *out;
char *in;
uint size;
{
uint i;
uint len = size;
for (i=0; i<size; i++) {
switch (*in) {
case 0:
*out++ = '\\';
*out++ = *in++;
len++;
break;
case '\\':
*out++ = '\\';
*out++ = *in++;
len++;
break;
case '\'':
*out++ = '\\';
*out++ = *in++;
len++;
break;
default:
*out++ = *in++;
}
}
*out = 0;
return len;
}
static uint
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;
return (uint)(s - field);
}
/********************************************************
***** MySQL methods
********************************************************/
static PyObject *
MySQL_connect(self, args)
PyObject *self, *args;
{
char *dbhost = NULL;
char *dbuser = NULL;
char *dbpass = NULL;
DBHObject *DBH;
MYSQL newhandle;
if (!PyArg_ParseTuple(args, "|sss:connect", &dbhost, &dbuser, &dbpass))
return NULL;
if (!(mysql_connect(&newhandle, dbhost, dbuser, dbpass))) {
PyErr_SetString(MySQLError, "connect(): could not connect to MySQL");
return NULL;
}
if (newhandle.net.error) {
PyErr_SetString(MySQLError, mysql_error(&newhandle));
return NULL;
} else {
DBH = PyObject_NEW(DBHObject, &MySQLType);
if (DBH == NULL)
return NULL;
DBH->valid = 1;
DBH->handle = newhandle;
DBH->dbh_use_result = 0;
DBH->cursor = NULL;
return ((PyObject *) DBH);
}
}
static PyObject *
MySQL_escape(self,args)
PyObject *self, *args;
{
char *in = NULL;
char *out = NULL;
PyObject *str;
uint size, len;
if (!PyArg_ParseTuple(args, "s#:escape", &in, &size))
return NULL;
out = (char *) malloc(size*2+1);
if (!out) {
PyErr_SetString(MySQLError, "escape(): no memory");
return NULL;
}
len = escape_chars(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 (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;
clear_channel(self);
if ((res = mysql_list_dbs(&(self->handle), wildcard)) == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
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;
clear_channel(self);
if ((res = mysql_list_tables(&(self->handle), wildcard)) == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
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;
clear_channel(self);
if ((res = mysql_list_fields(&(self->handle), tname, wildcard)) == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
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;
clear_channel(self);
if ((res = mysql_list_processes(&(self->handle))) == NULL) {
Py_INCREF(Py_None);
return (Py_None);
}
resobj = pythonify_res(res,-1);
mysql_free_result(res);
return (resobj);
}
static PyObject *
DBH_query_helper(self, query, size)
DBHObject *self;
char *query;
uint size;
{
MYSQL_RES *res;
PyObject *resobj;
clear_channel(self);
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));
self->cursor = res;
} else {
res = mysql_store_result(&(self->handle));
}
if (!res) {
/* code to handle returning of auto_increment keys */
if (mysql_error(&(self->handle))[0] == 0 &&
mysql_num_fields(&(self->handle)) == 0 &&
mysql_insert_id(&(self->handle)) != 0) {
ulong used_id;
used_id = mysql_insert_id(&(self->handle));
return (PyInt_FromLong(used_id));
} else {
Py_INCREF(Py_None);
return (Py_None);
}
}
resobj = pythonify_res(res,-1);
mysql_free_result(res);
return (resobj);
}
static PyObject *
DBH_do(self, args)
DBHObject *self;
PyObject *args;
{
char *query;
uint 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;
clear_channel(self);
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_stat(self, args)
DBHObject *self;
PyObject *args;
{
char *stat;
if (!PyArg_ParseTuple(args, ":stat"))
return NULL;
clear_channel(self);
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 :-(
clear_channel(self);
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;
clear_channel(self);
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;
clear_channel(self);
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;
clear_channel(self);
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;
clear_channel(self);
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;
clear_channel(self);
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;
clear_channel(self);
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;
{
MYSQL_RES *res;
char *query;
uint size;
PyObject *tmp;
int use_result = self->dbh_use_result;
if (!PyArg_ParseTuple(args, "s#|i:query", &query, &size, &use_result))
return NULL;
clear_channel(self);
if (mysql_real_query(&(self->handle), query, size)) {
PyErr_SetString(MySQLError, mysql_error(&(self->handle)));
return NULL;
}
if (use_result) {
res = mysql_use_result(&(self->handle));
self->cursor = res;
} else {
res = mysql_store_result(&(self->handle));
}
return STH(res,self->handle,use_result);
}
/* For DBH['query'] syntax */
static PyObject *
DBH_subscript(self, subs)
PyObject *self, *subs;
{
char *query;
uint 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},
{"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;
{
if (self->valid)
mysql_close(&(self->handle));
PyMem_DEL(self);
}
static PyTypeObject MySQLType =
{
PyObject_HEAD_INIT(&PyType_Type)
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;
{
if ((!PyArg_ParseTuple(args, ":fields")) || no_response(self))
return NULL;
return pythonify_res_fields(self->res);
}
static PyObject *
STH_fetchrows(self, args)
STHObject *self;
PyObject *args;
{
int i = -1;
if ((!PyArg_ParseTuple(args, "|i:fetchrows", &i)) || no_response(self))
return NULL;
if (i < 0) mysql_data_seek(self->res,0);
return pythonify_res(self->res, i);
}
static PyObject *
STH_fetchdict(self,args)
STHObject *self;
PyObject *args;
{
int i = -1;
int j = 0;
int tlen = 0;
int flen = 0;
int status;
int rows = 0;
int cols = 0;
char *fieldname;
MYSQL_FIELD *tf;
PyObject *rowdict;
PyObject *datalist;
PyObject *rowlist;
PyObject *value;
if ((!PyArg_ParseTuple(args, "|i:fetchdict", &i)) || no_response(self))
return NULL;
if (i < 0) mysql_data_seek(self->res,0);
datalist = pythonify_res(self->res,i);
if (datalist == NULL)
return NULL;
rows = PyList_Size(datalist);
if (rows == -1) {
Py_DECREF(datalist);
return NULL;
}
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) {
Py_DECREF(datalist);
PyErr_SetString(MySQLError, "fetchdict: mysql_fetch_field_direct() failed");
return NULL;
}
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(name)");
Py_DECREF(datalist);
return NULL;
}
for (i=0; i<rows; i++) {
rowdict = PyDict_New();
if (rowdict == NULL) {
Py_DECREF(datalist);
free(fieldname);
return NULL;
}
rowlist = PyList_GetItem(datalist,i);
if (rowlist == NULL) {
Py_DECREF(datalist);
free(fieldname);
return NULL;
}
for (j=0; j<cols; j++) {
tf = &(mysql_fetch_field_direct(self->res,j));
if (tf == NULL) {
Py_DECREF(datalist);
free(fieldname);
return NULL;
}
status = mystrcpy(fieldname,tf->table,".",tf->name);
value = PyList_GetItem(rowlist,j);
if (value == NULL) {
Py_DECREF(datalist);
free(fieldname);
return NULL;
}
status = PyDict_SetItemString(rowdict,fieldname,value);
if (status == -1) {
Py_DECREF(datalist);
free(fieldname);
return NULL;
}
}
status = PyList_SetItem(datalist,i,rowdict);
if (status == -1) {
Py_DECREF(datalist);
free(fieldname);
return NULL;
}
}
free(fieldname);
}
return (datalist);
}
static PyObject *
STH_seek(self, args)
STHObject *self;
PyObject *args;
{
uint 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(self->affected_rows);
}
static PyObject *
STH_insertid(self, args)
STHObject *self;
PyObject *args;
{
if (!PyArg_ParseTuple(args, ":insertid"))
return NULL;
return PyInt_FromLong(self->insert_id);
}
static PyObject *
STH(MYSQL_RES *res, MYSQL conn, int use_result)
{
STHObject *self;
self = PyObject_NEW(STHObject, &ResType);
if (self == NULL)
return NULL;
self->res = res;
self->affected_rows = conn.affected_rows;
self->insert_id = conn.insert_id;
self->sth_use_result = use_result;
return (PyObject *) self;
}
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 != NULL)
mysql_free_result(self->res);
PyMem_DEL(self);
}
static PyTypeObject ResType =
{
PyObject_HEAD_INIT(&PyType_Type)
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;
module = Py_InitModule("MySQL", MySQL_Methods);
dict = PyModule_GetDict(module);
if (PyDict_SetItemString(dict, "DbType", (PyObject *) & MySQLType) != 0)
Py_FatalError("Cannot add to MySQL dictionary");
if (PyDict_SetItemString(dict, "CursorType", (PyObject *) & ResType) != 0)
Py_FatalError("Cannot add to MySQL dictionary");
MySQLError = PyErr_NewException("MySQL.error",NULL,NULL);
if (PyDict_SetItemString(dict, "error", MySQLError) != 0)
Py_FatalError("Cannot add to MySQL dictionary");
}