diff --git a/mysql/MySQLdb.py b/mysql/MySQLdb.py index d24effd..c5ad732 100644 --- a/mysql/MySQLdb.py +++ b/mysql/MySQLdb.py @@ -4,22 +4,38 @@ This module is a thin wrapper around _mysql, which mostly implements the MySQL C API. All symbols from that module are imported. connect() -- connects to server -type_conv -- dictionary mapping SQL types to Python functions, which - convert a string into an appropriate data type. Reasonable - defaults are set for most items, and you can add your own. + +type_conv -- dictionary mapping SQL types (FIELD_TYPE) to Python functions, + which convert a string into an appropriate data type. Reasonable + defaults are set for most items, and you can add your own. + +quote_conv -- dictionary mapping Python types to functions. Function takes + one argument of the indicated type and a mapping argument, and returns + an SQL-quoted string. The mapping argument is only used for recursive + quoting (i.e. when quoting sequences). Most simple converters + will not need this and can ignore it. See the API specification and the MySQL documentation for more info on other items. -This module uses the mxDateTime package for handling date/time types. +This module uses the mx.DateTime package for handling date/time types, +if it is available. Otherwise, date types are returned as strings. """ -__version__ = """$Revision$"""[11:-2] +__author__ = "Andy Dustman " +__version__ = "0.3.6" +__revision__ = """$Revision$"""[11:-2] import _mysql from _mysql import * from time import localtime import re, types +from types import ListType, TupleType +from string import rfind, join, split, atoi + +if __version__ != _mysql.__version__: + raise ImportError, "this is MySQLdb version %s, but _mysql is version %s" %\ + (__version__, _mysql.__version__) threadsafety = 2 apilevel = "2.0" @@ -32,15 +48,28 @@ try: except ImportError: _threading = None -def Thing2Str(s, d={}): return str(s) -def Long2Int(l, d={}): s = str(l); return s[-1] == 'L' and s[:-1] or s -def None2NULL(o, d={}): return "NULL" -def Thing2Literal(o, d={}): return string_literal(str(o)) +def Thing2Str(s, d): + """Convert something into a string via str().""" + return str(s) -# MySQL-3.23.xx now has a new escape_string function that uses -# the connection to determine what character set is in use and -# quote accordingly. So this will be overridden by the connect() -# method. +# Python 1.5.2 compatibility hack +if str(0L)[-1]=='L': + def Long2Int(l, d): + """Convert a long integer to a string, chopping the L.""" + return str(l)[:-1] +else: + Long2Int = Thing2Str + +def None2NULL(o, d): + """Convert None to NULL.""" + return "NULL" # duh + +def Thing2Literal(o, d): + """Convert something into a SQL string literal. + If using MySQL-3.23 or newer, string_literal() is a method + of the _mysql.MYSQL object, and this function will be overridden + with that method when the connection is created.""" + return string_literal(str(o)) quote_conv = { types.IntType: Thing2Str, types.LongType: Long2Int, @@ -62,28 +91,40 @@ type_conv = { FIELD_TYPE.TINY: int, try: try: - from mx import DateTime # new packaging + # new packaging from mx.DateTime import Date, Time, Timestamp, ISO, \ DateTimeType, DateTimeDeltaType except ImportError: - import DateTime # old packaging + # old packaging from DateTime import Date, Time, Timestamp, ISO, \ DateTimeType, DateTimeDeltaType def DateFromTicks(ticks): + """Convert UNIX ticks into a mx.DateTime.Date.""" return apply(Date, localtime(ticks)[:3]) def TimeFromTicks(ticks): + """Convert UNIX ticks into a mx.DateTime.Time.""" return apply(Time, localtime(ticks)[3:6]) def TimestampFromTicks(ticks): + """Convert UNIX ticks into a mx.DateTime.Timestamp.""" return apply(Timestamp, localtime(ticks)[:6]) - def format_DATE(d): return d.strftime("%Y-%m-%d") - def format_TIME(d): return d.strftime("%H:%M:%S") - def format_TIMESTAMP(d): return d.strftime("%Y-%m-%d %H:%M:%S") + def format_DATE(d): + """Format a DateTime object as an ISO date.""" + return d.strftime("%Y-%m-%d") + + def format_TIME(d): + """Format a DateTime object as a time value.""" + return d.strftime("%H:%M:%S") + + def format_TIMESTAMP(d): + """Format a DateTime object as an ISO timestamp.""" + return d.strftime("%Y-%m-%d %H:%M:%S") def mysql_timestamp_converter(s): + """Convert a MySQL TIMESTAMP to a mx.DateTime.Timestamp.""" 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)) @@ -93,8 +134,13 @@ try: type_conv[FIELD_TYPE.TIME] = ISO.ParseTimeDelta type_conv[FIELD_TYPE.DATE] = ISO.ParseDate - def DateTime2literal(d, c={}): return "'%s'" % format_TIMESTAMP(d) - def DateTimeDelta2literal(d, c={}): return "'%s'" % format_TIME(d) + def DateTime2literal(d, c): + """Format a DateTime object as an ISO timestamp.""" + return "'%s'" % format_TIMESTAMP(d) + + def DateTimeDelta2literal(d, c): + """Format a DateTimeDelta object as a time.""" + return "'%s'" % format_TIME(d) quote_conv[DateTimeType] = DateTime2literal quote_conv[DateTimeDeltaType] = DateTimeDelta2literal @@ -104,19 +150,27 @@ except ImportError: from time import strftime def DateFromTicks(ticks): + """Convert UNIX ticks to ISO date format.""" return strftime("%Y-%m-%d", localtime(ticks)) def TimeFromTicks(ticks): + """Convert UNIX ticks to time format.""" return strftime("%H:%M:%S", localtime(ticks)) def TimestampFromTicks(ticks): + """Convert UNIX ticks to ISO timestamp format.""" return strftime("%Y-%m-%d %H:%M:%S", localtime(ticks)) - def format_DATE(d): return d + def format_DATE(d): + """Format a date as a date (does nothing, you don't have mx.DateTime).""" + return d + format_TIME = format_TIMESTAMP = format_DATE class DBAPITypeObject: + + """Helper class for determining column types; required by DB API.""" def __init__(self,*values): self.values = values @@ -165,26 +219,27 @@ class BaseCursor: self._thequery = '' def close(self): + """Close the cursor. No further queries will be possible.""" self.connection = None def _check_open(self): if not self.connection: raise ProgrammingError, "cursor closed" - def setinputsizes(self, *args): pass + def setinputsizes(self, *args): + """Does nothing, required by DB API.""" - def setoutputsizes(self, *args): pass + def setoutputsizes(self, *args): + """Does nothing, required by DB API.""" def execute(self, query, args=None): - """rows=cursor.execute(query, args=None) + """Execute a query. query -- string, query to execute on server args -- sequence or mapping, parameters to use with query. - rows -- rows affected, if any""" + returns long integer rows affected, if any""" self._check_open() self._thequery = query - from types import ListType, TupleType - from string import rfind, join, split, atoi qc = self.connection.quote_conv if not args: return self._query(query) @@ -201,13 +256,14 @@ class BaseCursor: raise def executemany(self, query, args): - """cursor.executemany(self, query, args) + """Execute a multi-row query. query -- string, query to execute on server args -- sequence of sequences or mappings, parameters to use with query. The query must contain the clause "values ( ... )". The parenthetical portion will be repeated once for each item in the sequence. + returns long integer rows affected, if any This method performs multiple-row inserts and similar queries.""" self._check_open() @@ -246,14 +302,18 @@ class BaseCursor: _query = __do_query def info(self): + """Return some information about the last query (db.info())""" try: return self._info except AttributeError: raise ProgrammingError, "execute() first" def insert_id(self): + """Return the last inserted ID on an AUTO_INCREMENT columns.""" try: return self._insert_id except AttributeError: raise ProgrammingError, "execute() first" - def nextset(self): return None + def nextset(self): + """Does nothing. Required by DB API.""" + return None def _fetch_row(self): r = self._result.fetch_row(1, self._fetch_type) @@ -268,6 +328,10 @@ class BaseCursor: class CursorWarningMixIn: + """This is a MixIn class that provides the capability of raising + the Warning exception when something went slightly wrong with your + query.""" + def _check_for_warnings(self): from string import atoi, split if self._info: @@ -278,9 +342,15 @@ class CursorWarningMixIn: class CursorStoreResultMixIn: + """This is a MixIn class which causes the entire result set to be + stored on the client side, i.e. it uses mysql_store_result(). If the + result set can be very large, consider adding a LIMIT clause to your + query, or using CursorUseResultMixIn instead.""" + def _get_result(self): return self.connection.db.store_result() def close(self): + """Close the cursor. Further queries will not be possible.""" self.connection = None self._rows = () @@ -304,9 +374,8 @@ class CursorStoreResultMixIn: return result def fetchmany(self, size=None): - """cursor.fetchmany(size=cursor.arraysize) - - size -- integer, maximum number of rows to fetch.""" + """Fetch up to size rows from the cursor. Result set may be smaller + than size. If size is not defined, cursor.arraysize is used.""" if not self._thequery: raise ProgrammingError, "execute() first" end = self._pos + size or self.arraysize result = self._rows[self._pos:end] @@ -321,6 +390,8 @@ class CursorStoreResultMixIn: return result def seek(self, row, whence=0): + """seek to a given row of the result set analogously to file.seek(). + This is non-standard extension.""" if whence == 0: self._pos = row elif whence == 1: @@ -328,17 +399,26 @@ class CursorStoreResultMixIn: elif whence == 2: self._pos = len(self._rows) + row - def tell(self): return self._pos + def tell(self): + """Return the current position in the result set analogously to + file.tell(). This is a non-standard extension.""" + return self._pos class CursorUseResultMixIn: + """This is a MixIn class which causes the result set to be stored in + the server and sent row-by-row to client side, i.e. it uses + mysql_use_result(). You MUST retrieve the entire result set and close() + the cursor before additional queries can be peformed on the connection.""" + def __init__(self, connection): BaseCursor.__init__(self, connection) if not self.connection._acquire(0): raise ProgrammingError, "would deadlock" def close(self): + """Close the cursor. No further queries can be executed.""" if self.connection: self.connection._release() self.connection = None @@ -357,9 +437,8 @@ class CursorUseResultMixIn: return self._fetch_row() def fetchmany(self, size=None): - """cursor.fetchmany(size=cursor.arraysize) - - size -- integer, maximum number of rows to fetch.""" + """Fetch up to size rows from the cursor. Result set may be smaller + than size. If size is not defined, cursor.arraysize is used.""" self._check_open() if not self._thequery: raise ProgrammingError, "execute() first" return self._fetch_rows(size or self.arraysize) @@ -373,57 +452,85 @@ class CursorUseResultMixIn: class CursorTupleRowsMixIn: + """This is a MixIn class that causes all rows to be returned as tuples, + which is the standard form required by DB API.""" + _fetch_type = 0 class CursorDictRowsMixIn: + """This is a MixIn class that causes all rows to be returned as + dictionaries. This is a non-standard feature.""" + _fetch_type = 1 - ## XXX Deprecated - def fetchoneDict(self, *args, **kwargs): + """Fetch a single row as a dictionary. Deprecated: + Use fetchone() instead.""" return apply(self.fetchone, args, kwargs) def fetchmanyDict(self, *args, **kwargs): + """Fetch several rows as a list of dictionaries. Deprecated: + Use fetchmany() instead.""" return apply(self.fetchmany, args, kwargs) def fetchallDict(self, *args, **kwargs): + """Fetch all available rows as a list of dictionaries. Deprecated: + Use fetchall() instead.""" return apply(self.fetchall, args, kwargs) class CursorOldDictRowsMixIn(CursorDictRowsMixIn): + """This is a MixIn class that returns rows as dictionaries with + the same key convention as the old Mysqldb (MySQLmodule). Don't + use this.""" + _fetch_type = 2 class CursorNW(CursorStoreResultMixIn, CursorTupleRowsMixIn, - BaseCursor): pass + BaseCursor): + """This is a basic Cursor class that returns rows as tuples and + stores the result set in the client. Warnings are not raised.""" -class Cursor(CursorWarningMixIn, CursorNW): pass +class Cursor(CursorWarningMixIn, CursorNW): + """This is the standard Cursor class that returns rows as tuples and + stores the result set in the client. Warnings are raised as necessary.""" class DictCursorNW(CursorStoreResultMixIn, CursorDictRowsMixIn, - BaseCursor): pass - -class DictCursor(CursorWarningMixIn, DictCursorNW): pass + BaseCursor): + """This is a Cursor class that returns rows as dictionaries and + stores the result set in the client. Warnings are not raised.""" +class DictCursor(CursorWarningMixIn, DictCursorNW): + """This is a Cursor class that returns rows as dictionaries and + stores the result set in the client. Warnings are raised as necessary.""" + class SSCursorNW(CursorUseResultMixIn, CursorTupleRowsMixIn, - BaseCursor): pass + BaseCursor): + """This is a basic Cursor class that returns rows as tuples and + stores the result set in the server. Warnings are not raised.""" -class SSCursor(CursorWarningMixIn, SSCursorNW): pass +class SSCursor(CursorWarningMixIn, SSCursorNW): + """This is a Cursor class that returns rows as tuples and + stores the result set in the server. Warnings are raised as necessary.""" class SSDictCursorNW(CursorUseResultMixIn, CursorDictRowsMixIn, - BaseCursor): pass + BaseCursor): + """This is a Cursor class that returns rows as dictionaries and + stores the result set in the server. Warnings are not raised.""" -class SSDictCursor(CursorWarningMixIn, SSDictCursorNW): pass +class SSDictCursor(CursorWarningMixIn, SSDictCursorNW): + """This is a Cursor class that returns rows as dictionaries and + stores the result set in the server. Warnings are raised as necessary.""" class Connection: - """Connection(host=NULL, user=NULL, passwd=NULL, db=NULL, - port=, unix_socket=NULL, client_flag=0) - - Note: This interface uses keyword arguments exclusively. + """Create a connection to the database. Note that this interface + uses keyword arguments exclusively. host -- string, host to connect to or NULL pointer (localhost) user -- string, user to connect as or NULL (your username) @@ -434,12 +541,18 @@ class Connection: client_flags -- integer, flags to use or 0 (see MySQL docs) conv -- dictionary, maps MySQL FIELD_TYPE.* to Python functions which convert a string to the appropriate Python type + connect_time -- number of seconds to wait before the connection + attempt fails. + compress -- if set, compression is enabled + init_command -- command which is run once the connection is created + read_default_file -- see the MySQL documentation for mysql_options() + read_default_group -- see the MySQL documentation for mysql_options() Returns a Connection object. Useful attributes and methods: - db -- connection object from _mysql. Good for accessing some of the + db -- _mysql.MYSQL connection object. Good for accessing some of the MySQL-specific calls. close -- close the connection. cursor -- create a cursor (emulated) for executing queries. @@ -467,7 +580,10 @@ class Connection: def _acquire(self, blocking=1): return 1 def _release(self): return 1 - def Thing2Literal(self, o, d={}): return self.db.string_literal(str(o)) + def Thing2Literal(self, o, d={}): + """Convert a thing to a string literal using the current + character set.""" + return self.db.string_literal(str(o)) def close(self): """Close the connection. No further activity possible.""" @@ -485,7 +601,9 @@ class Connection: else: raise NotSupportedError, "Not supported by server" def cursor(self, cursorclass=None): - """Create a cursor on which queries may be performed.""" + """Create a cursor on which queries may be performed. + The optional cursorclass parameter is used to create + the Cursor. By default, self.cursorclass=Cursor is used.""" return (cursorclass or self.cursorclass)(self) # Non-portable MySQL-specific stuff diff --git a/mysql/_mysql_const/__init__.py b/mysql/_mysql_const/__init__.py index 3da4a0e..b472651 100644 --- a/mysql/_mysql_const/__init__.py +++ b/mysql/_mysql_const/__init__.py @@ -1 +1 @@ -__all__ = ['CR', 'FIELD_TYPE','CLIENT','REFRESH','ER','FLAG'] +__all__ = ['exc','CR', 'FIELD_TYPE','CLIENT','REFRESH','ER','FLAG'] diff --git a/mysql/_mysql_const/exc.py b/mysql/_mysql_const/exc.py new file mode 100644 index 0000000..8ced64a --- /dev/null +++ b/mysql/_mysql_const/exc.py @@ -0,0 +1,59 @@ +"""_mysql_const.exc: Exception classes for _mysql and MySQLdb. + +These classes are dictated by the DB API v2.0: + + http://www.python.org/topics/database/DatabaseAPI-2.0.html +""" + +from exceptions import Exception, StandardError + +class MySQLError(StandardError): + """Exception related to operation with MySQL.""" + +class Warning(MySQLError): + """Exception raised for important warnings like data truncations + while inserting, etc.""" + +class Error(MySQLError): + """Exception that is the base class of all other error exceptions + (not Warning).""" + +class InterfaceError(Error): + """Exception raised for errors that are related to the database + interface rather than the database itself.""" + +class DatabaseError(Error): + """Exception raised for errors that are related to the database.""" + +class DataError(DatabaseError): + """Exception raised for errors that are due to problems with the + processed data like division by zero, numeric value out of range, etc.""" + +class OperationalError(DatabaseError): + """Exception raised for errors that are related to the database's + operation and not necessarily under the control of the programmer, + e.g. an unexpected disconnect occurs, the data source name is not + found, a transaction could not be processed, a memory allocation error + occurred during processing, etc.""" + +class IntegrityError(DatabaseError): + """Exception raised when the relational integrity of the database + is affected, e.g. a foreign key check fails, duplicate key, etc.""" + +class InternalError(DatabaseError): + """Exception raised when the database encounters an internal error, + e.g. the cursor is not valid anymore, the transaction is out of sync, + etc.""" + +class ProgrammingError(DatabaseError): + """Exception raised for programming errors, e.g. table not found or + already exists, syntax error in the SQL statement, wrong number of + parameters specified, etc.""" + +class NotSupportedError(DatabaseError): + """Exception raised in case a method or database API was used which + is not supported by the database, e.g. requesting a .rollback() on a + connection that does not support transaction or has transactions turned + off.""" + +del Exception, StandardError diff --git a/mysql/_mysqlmodule.c b/mysql/_mysqlmodule.c index 2794497..622599f 100644 --- a/mysql/_mysqlmodule.c +++ b/mysql/_mysqlmodule.c @@ -1,3 +1,4 @@ +static char _mysql__version__[] = "0.3.6"; /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -40,6 +41,7 @@ PERFORMANCE OF THIS SOFTWARE. #include "mysqld_error.h" #include "errmsg.h" +static PyObject *_mysql_MySQLError; static PyObject *_mysql_Warning; static PyObject *_mysql_Error; static PyObject *_mysql_DatabaseError; @@ -156,6 +158,27 @@ _mysql_ResultObject_New( return r; } +static char _mysql_connect__doc__[] = +"connect() -- takes a number of keyword arguments and\n\ +returns a MYSQL connection object.\n\ +\n\ +host -- string, host to connect to or NULL pointer (localhost)\n\ +user -- string, user to connect as or NULL (your username)\n\ +passwd -- string, password to use or NULL (no password)\n\ +db -- string, database to use or NULL (no DB selected)\n\ +port -- integer, TCP/IP port to connect to or default MySQL port\n\ +unix_socket -- string, location of unix_socket to use or use TCP\n\ +client_flags -- integer, flags to use or 0 (see MySQL docs)\n\ +conv -- dictionary, maps MySQL FIELD_TYPE.* to Python functions which\n\ + convert a string to the appropriate Python type\n\ +connect_time -- number of seconds to wait before the connection\n\ + attempt fails.\n\ +compress -- if set, compression is enabled\n\ +init_command -- command which is run once the connection is created\n\ +read_default_file -- see the MySQL documentation for mysql_options()\n\ +read_default_group -- see the MySQL documentation for mysql_options()\n\ +"; + static PyObject * _mysql_connect( PyObject *self, @@ -255,6 +278,12 @@ _mysql_ConnectionObject_affected_rows( return PyLong_FromUnsignedLongLong(mysql_affected_rows(&(self->connection))); } +static char _mysql_debug__doc__[] = +"debug(s) -- Does a DBUG_PUSH with the given string.\n\ +mysql_debug() uses the Fred Fish debug library.\n\ +To use this function, you must compile the client library to\n\ +support debugging.\n\ +"; static PyObject * _mysql_debug( PyObject *self, @@ -300,6 +329,15 @@ _mysql_ConnectionObject_error( return PyString_FromString(mysql_error(&(self->connection))); } +static char _mysql_escape_string__doc__[] = +"escape_string(s) -- quote any SQL-interpreted characters in string s.\n\ +\n\ +This function is somewhat deprecated. mysql_real_escape_string() was\n\ +introduced in MySQL-3.23. The new version handles character sets\n\ +correctly, but requires a connection object to work. Therefore,\n\ +escape_string() has become a method of the connection object. It is\n\ +retained as a module function for compatibility reasons. Use the\n\ +method version of this function if at all possible."; static PyObject * _mysql_escape_string( _mysql_ConnectionObject *self, @@ -324,13 +362,19 @@ _mysql_escape_string( return (str); } -/* In 3.23.x, mysql_escape_string() is deprecated for - * mysql_real_escape_string, which takes a connection - * as the first arg, so this needs to be a connection - * method. For backwards compatibility, it also needs - * to be a module function. - */ - +static char _mysql_string_literal__doc__[] = +"string_literal(obj) -- converts object obj into a SQL string literal.\n\ +This means, any special SQL characters are escaped, and it is enclosed\n\ +within single quotes. In other words, it performs:\n\ +\n\ +\"'%s'\" % escape_string(str(obj))\n\ +\n\ +This function is somewhat deprecated. mysql_real_escape_string() was\n\ +introduced in MySQL-3.23. The new version handles character sets\n\ +correctly, but requires a connection object to work. Therefore,\n\ +string_literal() has become a method of the connection object. It is\n\ +retained as a module function for compatibility reasons. Use the\n\ +method version of this function if at all possible."; static PyObject * _mysql_string_literal( _mysql_ConnectionObject *self, @@ -388,6 +432,10 @@ error: return quoted; } +static char _mysql_escape__doc__[] = +"escape(obj, dict) -- escape any special characters in object obj\n\ +using mapping dict to provide quoting functions for each type.\n\ +Returns a SQL literal string."; static PyObject * _mysql_escape( PyObject *self, @@ -404,6 +452,10 @@ _mysql_escape( return _escape_item(o, d); } +static char _mysql_escape_sequence__doc__[] = +"escape_sequence(seq, dict) -- escape any special characters in sequence\n\ +seq using mapping dict to provide quoting functions for each type.\n\ +Returns a tuple of escaped items."; static PyObject * _mysql_escape_sequence( PyObject *self, @@ -434,6 +486,10 @@ _mysql_escape_sequence( return NULL; } +static char _mysql_escape_dict__doc__[] = +"escape_sequence(d, dict) -- escape any special characters in\n\ +dictionary d using mapping dict to provide quoting functions for each type.\n\ +Returns a dictionary of escaped items."; static PyObject * _mysql_escape_dict( PyObject *self, @@ -775,6 +831,9 @@ _mysql_ConnectionObject_character_set_name( } #endif +static char _mysql_get_client_info__doc__[] = +"get_client_info() -- Returns a string that represents\n\ +the client library version."; static PyObject * _mysql_get_client_info( PyObject *self, @@ -784,16 +843,6 @@ _mysql_get_client_info( return PyString_FromString(mysql_get_client_info()); } -static PyObject * -_mysql_ConnectionObject_commit( - _mysql_ConnectionObject *self, - PyObject *args) -{ - if (!PyArg_NoArgs(args)) return NULL; - Py_INCREF(Py_None); - return Py_None; -} - static PyObject * _mysql_ConnectionObject_get_host_info( _mysql_ConnectionObject *self, @@ -1113,6 +1162,8 @@ _mysql_ConnectionObject_repr( return PyString_FromString(buf); } +static char _mysql_ResultObject_data_seek__doc__[] = +"data_seek(n) -- seek to row n of result set"; static PyObject * _mysql_ResultObject_data_seek( _mysql_ResultObject *self, @@ -1125,6 +1176,8 @@ _mysql_ResultObject_data_seek( return Py_None; } +static char _mysql_ResultObject_row_seek__doc__[] = +"row_seek(n) -- seek by offset n rows of result set"; static PyObject * _mysql_ResultObject_row_seek( _mysql_ResultObject *self, @@ -1139,6 +1192,8 @@ _mysql_ResultObject_row_seek( return Py_None; } +static char _mysql_ResultObject_row_tell__doc__[] = +"row_tell() -- return the current row number of the result set."; static PyObject * _mysql_ResultObject_row_tell( _mysql_ResultObject *self, @@ -1179,7 +1234,6 @@ static PyMethodDef _mysql_ConnectionObject_methods[] = { {"character_set_name", (PyCFunction)_mysql_ConnectionObject_character_set_name, 0}, #endif {"close", (PyCFunction)_mysql_ConnectionObject_close, 0}, - {"commit", (PyCFunction)_mysql_ConnectionObject_commit, 0}, {"dump_debug_info", (PyCFunction)_mysql_ConnectionObject_dump_debug_info, 0}, {"escape_string", (PyCFunction)_mysql_escape_string, 1}, {"error", (PyCFunction)_mysql_ConnectionObject_error, 0}, @@ -1215,9 +1269,12 @@ static struct memberlist _mysql_ConnectionObject_memberlist[] = { }; static PyMethodDef _mysql_ResultObject_methods[] = { - {"data_seek", (PyCFunction)_mysql_ResultObject_data_seek, 1}, - {"row_seek", (PyCFunction)_mysql_ResultObject_row_seek, 1}, - {"row_tell", (PyCFunction)_mysql_ResultObject_row_tell, 0}, + {"data_seek", (PyCFunction)_mysql_ResultObject_data_seek, + METH_VARARGS, _mysql_ResultObject_data_seek__doc__}, + {"row_seek", (PyCFunction)_mysql_ResultObject_row_seek, + METH_VARARGS, _mysql_ResultObject_row_seek__doc__}, + {"row_tell", (PyCFunction)_mysql_ResultObject_row_tell, + METH_VARARGS, _mysql_ResultObject_row_tell__doc__}, {"describe", (PyCFunction)_mysql_ResultObject_describe, 0}, {"fetch_row", (PyCFunction)_mysql_ResultObject_fetch_row, METH_VARARGS | METH_KEYWORDS}, {"field_flags", (PyCFunction)_mysql_ResultObject_field_flags, 0}, @@ -1331,31 +1388,61 @@ PyTypeObject _mysql_ResultObject_Type = { static PyMethodDef _mysql_methods[] = { - { "connect", (PyCFunction)_mysql_connect, METH_VARARGS | METH_KEYWORDS }, - { "debug", (PyCFunction)_mysql_debug, METH_VARARGS }, - { "escape", (PyCFunction)_mysql_escape, METH_VARARGS }, - { "escape_sequence", (PyCFunction)_mysql_escape_sequence, METH_VARARGS }, - { "escape_dict", (PyCFunction)_mysql_escape_dict, METH_VARARGS }, - { "escape_string", (PyCFunction)_mysql_escape_string, METH_VARARGS }, - { "string_literal", (PyCFunction)_mysql_string_literal, METH_VARARGS }, - { "get_client_info", (PyCFunction)_mysql_get_client_info }, + { "connect", + (PyCFunction)_mysql_connect, + METH_VARARGS | METH_KEYWORDS, + _mysql_connect__doc__ + }, + { "debug", + (PyCFunction)_mysql_debug, + METH_VARARGS, + _mysql_debug__doc__ + }, + { "escape", + (PyCFunction)_mysql_escape, + METH_VARARGS, + _mysql_escape__doc__ + }, + { "escape_sequence", + (PyCFunction)_mysql_escape_sequence, + METH_VARARGS, + _mysql_escape_sequence__doc__ + }, + { "escape_dict", + (PyCFunction)_mysql_escape_dict, + METH_VARARGS, + _mysql_escape_dict__doc__ + }, + { "escape_string", + (PyCFunction)_mysql_escape_string, + METH_VARARGS, + _mysql_escape_string__doc__ + }, + { "string_literal", + (PyCFunction)_mysql_string_literal, + METH_VARARGS, + _mysql_string_literal__doc__ + }, + { "get_client_info", + (PyCFunction)_mysql_get_client_info, + 0, + _mysql_get_client_info__doc__ + }, {NULL, NULL} /* sentinel */ }; static PyObject * _mysql_NewException( PyObject *dict, - char *name, - PyObject *base) + PyObject *edict, + char *name) { - PyObject *v; - char longname[256]; + PyObject *e; - sprintf(longname, "_mysql.%s", name); - if ((v = PyErr_NewException(longname, base, NULL)) == NULL) + if (!(e = PyDict_GetItemString(edict, name))) return NULL; - if (PyDict_SetItemString(dict, name, v)) return NULL; - return v; + if (PyDict_SetItemString(dict, name, e)) return NULL; + return e; } int @@ -1387,76 +1474,60 @@ return result objects (MYSQL_RES). Functions which expect MYSQL_RES * as\n\ an argument are now methods of the result object. The mysql_real_*\n\ functions are the ones used in place of not-real ones. The various\n\ FLAG_*, CLIENT_*, FIELD_TYPE_*, etc. constants are renamed to FLAG.*,\n\ -CLIENT.*, FIELD_TYPE.*, etc. Deprecated functions are NOT implemented.\n\ -\n\ -type_conv is a dictionary which maps FIELD_TYPE.* to Python functions\n\ -which convert a string to some value. This is used by the fetch_row method.\n\ -Types not mapped are returned as strings. Numbers are all converted\n\ -reasonably, except DECIMAL.\n\ -\n\ -result.describe() produces a DB API description of the rows.\n\ -\n\ -escape_sequence() accepts a sequence of items and a type conversion dictionary.\n\ -Using the type of the item, it gets a converter function from the dictionary\n\ -(uses the string type if the item type is not found) and applies this to the\n\ -item. the result should be converted to strings with all the necessary\n\ -quoting.\n\ -\n\ -mysql_escape_string() on them, and returns them as a tuple.\n\ -\n\ -result.field_flags() returns the field flags for the result.\n\ -\n\ -result.fetch_row([n=0[, how=1]]) fetches up to n rows (default: n=1)\n\ -as a tuple of tuples (default: how=0) or dictionaries (how=1).\n\ -MySQL returns strings, but fetch_row() does data conversion\n\ -according to type_conv.\n\ -\n\ -For everything else, check the MySQL docs." ; +CLIENT.*, FIELD_TYPE.*, etc. Deprecated functions (as of 3.22) are NOT\n\ +implemented.\n\ +"; DL_EXPORT(void) init_mysql(void) { - PyObject *dict, *module; + PyObject *dict, *module, *emod, *edict; module = Py_InitModule3("_mysql", _mysql_methods, _mysql___doc__); #ifdef MS_WIN32 _mysql_ConnectionObject_Type.ob_type = &PyType_Type; _mysql_ResultObject_Type.ob_type = &PyType_Type; #endif - dict = PyModule_GetDict(module); + if (!(dict = PyModule_GetDict(module))) goto error; + if (PyDict_SetItemString(dict, "__version__", + PyString_FromString(_mysql__version__))) + goto error; + if (!(emod = PyImport_ImportModule("_mysql_const.exc"))) + goto error; + if (!(edict = PyModule_GetDict(emod))) goto error; + if (!(_mysql_MySQLError = + _mysql_NewException(dict, edict, "MySQLError"))) + goto error; if (!(_mysql_Warning = - _mysql_NewException(dict, "Warning", PyExc_StandardError))) + _mysql_NewException(dict, edict, "Warning"))) goto error; if (!(_mysql_Error = - _mysql_NewException(dict, "Error", PyExc_StandardError))) + _mysql_NewException(dict, edict, "Error"))) goto error; if (!(_mysql_InterfaceError = - _mysql_NewException(dict, "InterfaceError", _mysql_Error))) + _mysql_NewException(dict, edict, "InterfaceError"))) goto error; if (!(_mysql_DatabaseError = - _mysql_NewException(dict, "DatabaseError", _mysql_Error))) + _mysql_NewException(dict, edict, "DatabaseError"))) goto error; if (!(_mysql_DataError = - _mysql_NewException(dict, "DataError", _mysql_DatabaseError))) + _mysql_NewException(dict, edict, "DataError"))) goto error; if (!(_mysql_OperationalError = - _mysql_NewException(dict, "OperationalError", - _mysql_DatabaseError))) + _mysql_NewException(dict, edict, "OperationalError"))) goto error; if (!(_mysql_IntegrityError = - _mysql_NewException(dict, "IntegrityError", - _mysql_DatabaseError))) + _mysql_NewException(dict, edict, "IntegrityError"))) goto error; if (!(_mysql_InternalError = - _mysql_NewException(dict, "InternalError", - _mysql_DatabaseError))) - goto error; + _mysql_NewException(dict, edict, "InternalError"))) if (!(_mysql_ProgrammingError = - _mysql_NewException(dict, "ProgrammingError", - _mysql_DatabaseError))) + _mysql_NewException(dict, edict, "ProgrammingError"))) goto error; if (!(_mysql_NotSupportedError = - _mysql_NewException(dict, "NotSupportedError", - _mysql_DatabaseError))) + _mysql_NewException(dict, edict, "NotSupportedError"))) + goto error; + Py_DECREF(emod); + if (_mysql_Constant_class(dict, "_mysql_const.exc", "exc")) goto error; if (_mysql_Constant_class(dict, "_mysql_const.FLAG", "FLAG")) goto error; diff --git a/mysql/setup.py b/mysql/setup.py index 76727d8..e3fd429 100644 --- a/mysql/setup.py +++ b/mysql/setup.py @@ -24,7 +24,7 @@ if sys.platform == "linux-i386": # Red Hat libraries = [mysqlclient, "z"] runtime_library_dirs = [] extra_objects = [] -elif sys.platform == "freebsd4": +elif sys.platform in ("freebsd4", "openbsd2"): include_dirs = ['/usr/local/include/mysql'] library_dirs = ['/usr/local/lib/mysql'] libraries = [mysqlclient, "z"] @@ -85,6 +85,7 @@ setup (# Distribution meta-data # Description of the modules and packages in the distribution py_modules = ["MySQLdb", "CompatMysqldb", + "_mysql_const.exc", "_mysql_const.CR", "_mysql_const.FIELD_TYPE", "_mysql_const.ER",