Some errorhandler cleanups

This commit is contained in:
adustman
2002-06-23 20:25:55 +00:00
parent 07d1188b20
commit 3500b3d191
3 changed files with 90 additions and 52 deletions

View File

@ -1,3 +1,7 @@
0.9.2c2
* errorhandler cleanups (Rob Steele)
0.9.2c1 0.9.2c1
* If using Python 2.2 or newer, the _mysql connection object is * If using Python 2.2 or newer, the _mysql connection object is

View File

@ -16,18 +16,20 @@ import types, _mysql
def defaulterrorhandler(connection, cursor, errorclass, errorvalue): def defaulterrorhandler(connection, cursor, errorclass, errorvalue):
""" """
If cursor is not None, errorvalue is appended to cursor.messages; If cursor is not None, (errorclass, errorvalue) is appended to
otherwise it is appended to connection.messages. Then errorclass cursor.messages; otherwise it is appended to
is raised with errorvalue as the value. connection.messages. Then errorclass is raised with errorvalue as
the value.
You can override this with your own error handler by assigning it You can override this with your own error handler by assigning it
to the instance. to the instance.
""" """
error = errorclass, errorvalue
if cursor: if cursor:
cursor.messages.append(errorvalue) cursor.messages.append(error)
else: else:
connection.messages.append(errorvalue) connection.messages.append(error)
raise errorclass, errorvalue raise errorclass, errorvalue
@ -132,7 +134,8 @@ class Connection(ConnectionBase):
if self._transactional: if self._transactional:
self.query("ROLLBACK") self.query("ROLLBACK")
else: else:
raise NotSupportedError, "Not supported by server" self.errorhandler(None,
NotSupportedError, "Not supported by server")
def cursor(self, cursorclass=None): def cursor(self, cursorclass=None):
""" """

View File

@ -17,7 +17,6 @@ if hasattr(exceptions, "StopIteration"):
else: else:
_EndOfData = exceptions.IndexError _EndOfData = exceptions.IndexError
class BaseCursor: class BaseCursor:
"""A base for Cursor classes. Useful attributes: """A base for Cursor classes. Useful attributes:
@ -40,24 +39,36 @@ class BaseCursor:
self.lastrowid = None self.lastrowid = None
self.messages = [] self.messages = []
self.errorhandler = connection.errorhandler self.errorhandler = connection.errorhandler
self._result = None
def __del__(self): def __del__(self):
self.close() self.close()
def close(self): def close(self):
"""Close the cursor. No further queries will be possible.""" """Close the cursor. No further queries will be possible."""
if not self.connection: return
del self.messages[:]
self.nextset()
self.connection = None self.connection = None
self.errorhandler = None self.errorhandler = None
self._result = None
def _check_executed(self): def _check_executed(self):
if not self._executed: if not self._executed:
self.errorhandler(self.connection, self, self.errorhandler(self, ProgrammingError, "execute() first")
ProgrammingError, "execute() first")
def nextset(self): def nextset(self):
"""Advance to the next result set. Returns None if there are """Advance to the next result set.
no more result sets. Note that MySQL does not support multiple
result sets at this time.""" Returns None if there are no more result sets.
Note that MySQL does not support multiple result sets at this
time.
"""
del self.messages[:]
if self._executed:
self.fetchall()
return None return None
def setinputsizes(self, *args): def setinputsizes(self, *args):
@ -68,32 +79,37 @@ class BaseCursor:
def _get_db(self): def _get_db(self):
if not self.connection: if not self.connection:
self.errorhandler(self.connection, self, self.errorhandler(self, ProgrammingError, "cursor closed")
ProgrammingError, "cursor closed")
return self.connection return self.connection
def execute(self, query, args=None): def execute(self, query, args=()):
"""Execute a query. """Execute a query.
query -- string, query to execute on server query -- string, query to execute on server
args -- optional sequence or mapping, parameters to use with query. args -- optional sequence or mapping, parameters to use with query.
returns long integer rows affected, if any"""
Note: If args is a sequence, then %s must be used as the
parameter placeholder in the query. If a mapping is used,
%(key)s must be used as the placeholder.
Returns long integer rows affected, if any
"""
from types import ListType, TupleType from types import ListType, TupleType
if args is None: from sys import exc_info
r = self._query(query) del self.messages[:]
elif type(args) is ListType and type(args[0]) is TupleType: try:
r = self.executemany(query, args) # deprecated r = self._query(query % self.connection.literal(args))
else: except TypeError, m:
try: if m.args[0] in ("not enough arguments for format string",
r = self._query(query % self.connection.literal(args)) "not all arguments converted"):
except TypeError, m: self.errorhandler(self, ProgrammingError, m.args[0])
if m.args[0] in ("not enough arguments for format string", else:
"not all arguments converted"): self.errorhandler(self, TypeError, m)
self.errorhandler(self, ProgrammingError, m.args[0]) except:
else: e = exc_info()
raise self.errorhandler(self, e[0], e[1])
self._executed = query self._executed = query
return r return r
@ -102,15 +118,22 @@ class BaseCursor:
"""Execute a multi-row query. """Execute a multi-row query.
query -- string, query to execute on server 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."""
args
Sequence of sequences or mappings, parameters to use with
query.
Returns long integer rows affected, if any.
This method improves performance on multiple-row INSERT and
REPLACE. Otherwise it is equivalent to looping over args with
execute().
"""
from string import join from string import join
from sys import exc_info
del self.messages[:]
if not args: return if not args: return
m = insert_values.search(query) m = insert_values.search(query)
if not m: if not m:
@ -127,10 +150,12 @@ class BaseCursor:
except TypeError, msg: except TypeError, msg:
if msg.args[0] in ("not enough arguments for format string", if msg.args[0] in ("not enough arguments for format string",
"not all arguments converted"): "not all arguments converted"):
self.errorhandler(self.connection, self, self.errorhandler(self, ProgrammingError, msg.args[0])
ProgrammingError, msg.args[0])
else: else:
raise self.errorhandler(self, TypeError, msg)
except:
e = exc_info()
self.errorhandler(self, e[0], e[1])
r = self._query(join(q,',\n')) r = self._query(join(q,',\n'))
self._executed = query self._executed = query
return r return r
@ -145,8 +170,6 @@ class BaseCursor:
self.rownumber = 0 self.rownumber = 0
self.description = self._result and self._result.describe() or None self.description = self._result and self._result.describe() or None
self.lastrowid = db.insert_id() self.lastrowid = db.insert_id()
message = db.info()
if message: self.messages.append(message)
self._check_for_warnings() self._check_for_warnings()
return self.rowcount return self.rowcount
@ -159,7 +182,7 @@ class BaseCursor:
DEPRECATED: Use messages attribute""" DEPRECATED: Use messages attribute"""
self._check_executed() self._check_executed()
if self.messages: if self.messages:
return self.messages[0] return self.messages[-1]
else: else:
return '' return ''
@ -170,6 +193,8 @@ class BaseCursor:
return self.lastrowid return self.lastrowid
def _fetch_row(self, size=1): def _fetch_row(self, size=1):
if not self._result:
return ()
return self._result.fetch_row(size, self._fetch_type) return self._result.fetch_row(size, self._fetch_type)
def next(self): def next(self):
@ -203,10 +228,12 @@ class CursorWarningMixIn:
def _check_for_warnings(self): def _check_for_warnings(self):
from string import atoi, split from string import atoi, split
if self.messages: info = self._get_db().info()
warnings = atoi(split(self.messages[0])[-1]) if info is None:
if warnings: return
raise Warning, self.messages[0] warnings = atoi(split(info)[-1])
if warnings:
raise Warning, info
class CursorStoreResultMixIn: class CursorStoreResultMixIn:
@ -225,12 +252,13 @@ class CursorStoreResultMixIn:
def _query(self, q): def _query(self, q):
rowcount = self._BaseCursor__do_query(q) rowcount = self._BaseCursor__do_query(q)
self._rows = self._result and self._fetch_row(0) or () self._rows = self._fetch_row(0)
del self._result self._result = None
return rowcount return rowcount
def fetchone(self): def fetchone(self):
"""Fetches a single row from the cursor.""" """Fetches a single row from the cursor. None indicates that
no more rows are available."""
self._check_executed() self._check_executed()
if self.rownumber >= len(self._rows): return None if self.rownumber >= len(self._rows): return None
result = self._rows[self.rownumber] result = self._rows[self.rownumber]
@ -284,9 +312,10 @@ class CursorStoreResultMixIn:
elif mode == 'absolute': elif mode == 'absolute':
r = value r = value
else: else:
raise ProgrammingError, "unknown scroll mode %s" % `mode` self.errorhandler(self, ProgrammingError,
"unknown scroll mode %s" % `mode`)
if r < 0 or r >= len(self._rows): if r < 0 or r >= len(self._rows):
raise IndexError, "out of range" self.errorhandler(self, IndexError, "out of range")
self.rownumber = r self.rownumber = r
@ -300,6 +329,8 @@ class CursorUseResultMixIn:
def close(self): def close(self):
"""Close the cursor. No further queries can be executed.""" """Close the cursor. No further queries can be executed."""
del self.messages[:]
self.nextset()
self._result = None self._result = None
BaseCursor.close(self) BaseCursor.close(self)