From e1970cf20b736d4b1eab82f8c657daccfe83558b Mon Sep 17 00:00:00 2001 From: adustman Date: Wed, 17 Mar 1999 02:20:42 +0000 Subject: [PATCH] Updated _mysql to do some type conversion. Adds a dictionary type_conv which makes MySQL field types to Python functions which perform the conversion. All numeric types except DECIMAL are mapped into either PyInt or PyLong, and the floating point types are mapped into PyFloat by default. Types which are not represented in the dictionary are returned as strings. Modified MySQLdb to adjust type_conv so that the various date/time types are returned as DateTime objects. Bug: If you were to delete or assign type_conv, bad things would happen. I haven't actually tried this, but it wouldn't be good. May add an extra reference count to prevent this, haven't really decided. --- mysql/MySQLdb.py | 10 ++- mysql/_mysqlmodule.c | 178 ++++++++++++++++++++++++++----------------- 2 files changed, 119 insertions(+), 69 deletions(-) diff --git a/mysql/MySQLdb.py b/mysql/MySQLdb.py index 772800a..591b077 100644 --- a/mysql/MySQLdb.py +++ b/mysql/MySQLdb.py @@ -1,11 +1,19 @@ import _mysql from _mysql import * -from DateTime import Date, Time, Timestamp +from DateTime import Date, Time, Timestamp, ISO from types import StringType, ListType, TupleType threadsafety = 1 apllevel = "1.1" +def mysql_timestamp_converter(s): + parts = map(int, filter(None, (s[:4],s[4:6],s[6:8],s[8:10],s[10:12],s[12:14]))) + return apply(Timestamp, tuple(parts)) + +type_conv[FIELD_TYPE.TIMESTAMP] = mysql_timestamp_converter +type_conv[FIELD_TYPE.DATETIME] = ISO.ParseDateTime +type_conv[FIELD_TYPE.TIME] = ISO.ParseTime +type_conv[FIELD_TYPE.DATE] = ISO.ParseDate class Cursor: diff --git a/mysql/_mysqlmodule.c b/mysql/_mysqlmodule.c index b9ad74a..5832563 100644 --- a/mysql/_mysqlmodule.c +++ b/mysql/_mysqlmodule.c @@ -26,10 +26,14 @@ typedef struct { PyObject *conn; MYSQL *connection; MYSQL_RES *result; + int nfields; + PyObject **converter; } _mysql_ResultObject; extern PyTypeObject _mysql_ResultObject_Type; +static PyObject *_mysql_type_conv; + PyObject * _mysql_Exception(c) _mysql_ConnectionObject *c; @@ -132,6 +136,18 @@ static _mysql_Constant _mysql_Constant_field_type[] = { { NULL } /* sentinel */ } ; +static _mysql_Constant _mysql_Constant_type_conv[] = { + { "int", FIELD_TYPE_TINY }, + { "int", FIELD_TYPE_SHORT }, + { "int", FIELD_TYPE_LONG }, + { "float", FIELD_TYPE_FLOAT }, + { "float", FIELD_TYPE_DOUBLE }, + { "long", FIELD_TYPE_LONGLONG }, + { "int", FIELD_TYPE_INT24 }, + { "int", FIELD_TYPE_YEAR }, + { NULL } /* sentinel */ +} ; + static _mysql_Constant _mysql_Constant_cr[] = { { "UNKNOWN_ERROR", CR_UNKNOWN_ERROR }, { "SOCKET_CREATE_ERROR", CR_SOCKET_CREATE_ERROR }, @@ -322,6 +338,39 @@ static _mysql_Constant _mysql_Constant_er[] = { { NULL } /* sentinel */ } ; +static _mysql_ResultObject* +_mysql_ResultObject_New(conn, result) + _mysql_ConnectionObject *conn; + MYSQL_RES *result; +{ + int n, i; + MYSQL_FIELD *fields; + _mysql_ResultObject *r; + if (!(r = PyObject_NEW(_mysql_ResultObject, &_mysql_ResultObject_Type))) + return NULL; + r->connection = &conn->connection; + r->conn = (PyObject *) conn; + r->converter = NULL; + Py_INCREF(conn); + r->result = result; + n = mysql_num_fields(result); + r->nfields = n; + if (n) { + r->converter = PyMem_Malloc(n*sizeof(PyObject *)); + fields = mysql_fetch_fields(result); + r->fields = fields; + for (i=0; iconverter[i] = fun; + Py_XINCREF(fun); + Py_DECREF(tmp); + } + } + return r; +} + static PyObject * _mysql_connect(self, args, kwargs) PyObject *self; @@ -570,7 +619,13 @@ _mysql_ResultObject_fetch_row(self, args) for (i=0; iconverter[i]) + v = PyObject_CallFunction(self->converter[i], + "s#", + row[i], length[i]); + else + v = PyString_FromStringAndSize(row[i], + length[i]); if (!v) goto error; } else { @@ -668,23 +723,15 @@ _mysql_ConnectionObject_list_dbs(self, args) _mysql_ConnectionObject *self; PyObject *args; { - _mysql_ResultObject *r; + MYSQL_RES *result; char *wild = NULL; if (!PyArg_ParseTuple(args, "|s:list_dbs", &wild)) return NULL; - if (!(r = PyObject_NEW(_mysql_ResultObject, &_mysql_ResultObject_Type))) - return NULL; - r->connection = &(self->connection); - r->conn = (PyObject *) self; - Py_INCREF(self); Py_BEGIN_ALLOW_THREADS - r->result = mysql_list_dbs(&(self->connection), wild); + result = mysql_list_dbs(&(self->connection), wild); Py_END_ALLOW_THREADS - if (!(r->result)) { - Py_DECREF(r); - return _mysql_Exception(self); - } - return (PyObject *) r; + if (!result) return _mysql_Exception(self); + return (PyObject *) _mysql_ResultObject_New(self, result); } static PyObject * @@ -693,22 +740,15 @@ _mysql_ConnectionObject_list_fields(self, args) PyObject *args; { _mysql_ResultObject *r; + MYSQL_RES *result; char *wild = NULL, *table; if (!PyArg_ParseTuple(args, "s|s:list_fields", &table, &wild)) return NULL; - if (!(r = PyObject_NEW(_mysql_ResultObject, &_mysql_ResultObject_Type))) - return NULL; - r->connection = &(self->connection); - r->conn = (PyObject *) self; - Py_INCREF(self); Py_BEGIN_ALLOW_THREADS - r->result = mysql_list_fields(&(self->connection), table, wild); + result = mysql_list_fields(&(self->connection), table, wild); Py_END_ALLOW_THREADS - if (!(r->result)) { - Py_DECREF(r); - return _mysql_Exception(self); - } - return (PyObject *) r; + if (!result) return _mysql_Exception(self); + return (PyObject *) _mysql_ResultObject_New(self, result); } static PyObject * @@ -716,22 +756,14 @@ _mysql_ConnectionObject_list_processes(self, args) _mysql_ConnectionObject *self; PyObject *args; { - _mysql_ResultObject *r; + MYSQL_RES *result; if (!PyArg_NoArgs(args)) return NULL; - if (!(r = PyObject_NEW(_mysql_ResultObject, &_mysql_ResultObject_Type))) - return NULL; - r->connection = &self->connection; - r->conn = (PyObject *) self; - Py_INCREF(self); Py_BEGIN_ALLOW_THREADS - r->result = mysql_list_processes(&(self->connection)); + result = mysql_list_processes(&(self->connection)); Py_END_ALLOW_THREADS - if (!(r->result)) { - Py_DECREF(r); - return _mysql_Exception(self); - } - return (PyObject *) r; + if (!result) return _mysql_Exception(self); + return (PyObject *) _mysql_ResultObject_New(self, result); } static PyObject * @@ -739,23 +771,15 @@ _mysql_ConnectionObject_list_tables(self, args) _mysql_ConnectionObject *self; PyObject *args; { - _mysql_ResultObject *r; + MYSQL_RES *result; char *wild = NULL; if (!PyArg_ParseTuple(args, "|s:list_tables", &wild)) return NULL; - if (!(r = PyObject_NEW(_mysql_ResultObject, &_mysql_ResultObject_Type))) - return NULL; - r->connection = &self->connection; - r->conn = (PyObject *) self; - Py_INCREF(self); Py_BEGIN_ALLOW_THREADS - r->result = mysql_list_tables(&(self->connection), wild); + result = mysql_list_tables(&(self->connection), wild); Py_END_ALLOW_THREADS - if (!(r->result)) { - Py_DECREF(r); - return _mysql_Exception(self); - } - return (PyObject *) r; + if (!result) return _mysql_Exception(self); + return (PyObject *) _mysql_ResultObject_New(self, result); } static PyObject * @@ -879,24 +903,18 @@ _mysql_ConnectionObject_store_result(self, args) _mysql_ConnectionObject *self; PyObject *args; { - _mysql_ResultObject *r; + MYSQL_RES *result; unsigned int n; if (!PyArg_NoArgs(args)) return NULL; - if (!(r = PyObject_NEW(_mysql_ResultObject, &_mysql_ResultObject_Type))) - return NULL; - r->connection = &self->connection; - r->conn = (PyObject *) self; - Py_INCREF(self); Py_BEGIN_ALLOW_THREADS - r->result = mysql_store_result(&(self->connection)); + result = mysql_store_result(&(self->connection)); Py_END_ALLOW_THREADS - if (!(r->result)) { - Py_DECREF(r); + if (!result) { Py_INCREF(Py_None); return Py_None; } - return (PyObject *) r; + return (PyObject *) _mysql_ResultObject_New(self, result); } static PyObject * @@ -917,23 +935,17 @@ _mysql_ConnectionObject_use_result(self, args) _mysql_ConnectionObject *self; PyObject *args; { - _mysql_ResultObject *r; + MYSQL_RES *result; if (!PyArg_NoArgs(args)) return NULL; - if (!(r = PyObject_NEW(_mysql_ResultObject, &_mysql_ResultObject_Type))) - return NULL; - r->connection = &(self->connection); - r->conn = (PyObject *) self; - Py_INCREF(self); Py_BEGIN_ALLOW_THREADS - r->result = mysql_use_result(&(self->connection)); + result = mysql_use_result(&(self->connection)); Py_END_ALLOW_THREADS - if (!(r->result)) { - Py_DECREF(r); + if (!result) { Py_INCREF(Py_None); return Py_None; } - return (PyObject *) r; + return (PyObject *) _mysql_ResultObject_New(self, result); } static void @@ -978,8 +990,11 @@ static void _mysql_ResultObject_dealloc(self) _mysql_ResultObject *self; { + int i; if (self->result) mysql_free_result(self->result); Py_DECREF(self->conn); + for (i=0; infields; i++) Py_XDECREF(self->converter[i]); + PyMem_Free((char *) self->converter); PyMem_Free((char *) self); } @@ -1158,6 +1173,31 @@ _mysql_Constant_class(mdict, type, table) if (!(c = PyClass_New(NULL,d,PyString_InternFromString(type)))) goto error; if (PyDict_SetItemString(mdict, type, c)) goto error; return 0; + error: + Py_XDECREF(d); + return -1; +} + +int +_mysql_Constant_type_converters(mdict) + PyObject *mdict; +{ + PyObject *d, *v, *k, *m, *e; + int i; + /* XXX This leaks memory if it fails, but then the whole module + fails to import, so probably no big deal */ + if (!(d = PyDict_New())) goto error; + if (PyDict_SetItemString(mdict, "type_conv", d)) goto error; + if (!(m = PyImport_AddModule("__main__"))) goto error; + if (!(e = PyModule_GetDict(m))) goto error; + for (i = 0; _mysql_Constant_type_conv[i].name; i++) { + if (!(k = PyInt_FromLong((long)_mysql_Constant_type_conv[i].value))) goto error; + if (!(v = PyRun_String(_mysql_Constant_type_conv[i].name, Py_eval_input, e, e))) goto error; + if (!PyCallable_Check(v)) goto error; + if (PyDict_SetItem(d, k, v)) goto error; + } + _mysql_type_conv = d; + return 0; error: return -1; } @@ -1206,6 +1246,8 @@ init_mysql() if (!(_mysql_NULL = PyString_FromString("NULL"))) goto error; if (PyDict_SetItemString(dict, "NULL", _mysql_NULL)) goto error; + if (_mysql_Constant_type_converters(dict)) + goto error; error: if (PyErr_Occurred()) PyErr_SetString(PyExc_ImportError,