Mercurial > p > mysql-python > mysqldb-2
changeset 57:9ea2b0e9302e MySQLdb
The pure Python SQL-to-Python conversion code. TODO: There should be a way to register plugins in the module and in the connection.
author | adustman |
---|---|
date | Sat, 28 Feb 2009 04:06:44 +0000 |
parents | 89b07ce2a788 |
children | 6732437eb2ac |
files | MySQLdb/converters.py MySQLdb/cursors.py |
diffstat | 2 files changed, 78 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/MySQLdb/converters.py Fri Feb 27 19:46:55 2009 +0000 +++ b/MySQLdb/converters.py Sat Feb 28 04:06:44 2009 +0000 @@ -125,6 +125,13 @@ set: Set_to_sql, str: object_to_quoted_sql, # default + } + +# This is for MySQL column types that can be converted directly +# into Python types without having to look at metadata (flags, +# character sets, etc.). This should always be used as the last +# resort. +simple_sql_to_python_conversions = { FIELD_TYPE.TINY: int, FIELD_TYPE.SHORT: int, FIELD_TYPE.LONG: int, @@ -139,21 +146,62 @@ FIELD_TYPE.TIMESTAMP: mysql_timestamp_converter, FIELD_TYPE.DATETIME: datetime_or_None, FIELD_TYPE.TIME: timedelta_or_None, - FIELD_TYPE.DATE: date_or_None, - FIELD_TYPE.BLOB: [ - (FLAG.BINARY, str), - ], - FIELD_TYPE.STRING: [ - (FLAG.BINARY, str), - ], - FIELD_TYPE.VAR_STRING: [ - (FLAG.BINARY, str), - ], - FIELD_TYPE.VARCHAR: [ - (FLAG.BINARY, str), - ], + FIELD_TYPE.DATE: date_or_None, } +# Converter plugin protocol +# Each plugin is passed a cursor object and a field object. +# The plugin returns a single value: +# A callable that given an SQL value, returns a Python object. +# This can be as simple as int or str, etc. If the plugin +# returns None, this plugin will be ignored and the next plugin +# on the stack will be checked. + +def filter_NULL(f): + def _filter_NULL(o): + if o is None: return o + return f(o) + _filter_NULL.__name__ = f.__name__ + return _filter_NULL + +def sql_to_python_last_resort_plugin(cursor, field): + return str + +def simple_sql_to_python_plugin(cursor, field): + return simple_sql_to_python_conversions.get(field.type, None) + +character_types = [ + FIELD_TYPE.BLOB, + FIELD_TYPE.STRING, + FIELD_TYPE.VAR_STRING, + FIELD_TYPE.VARCHAR, + ] + +def character_sql_to_python_plugin(cursor, field): + if field.type not in character_types: + return None + if field.flags & FLAG.BINARY: + return str + + charset = cursor.connection.character_set_name() + def char_to_unicode(s): + return s.decode(charset) + + return char_to_unicode + +sql_to_python_plugins = [ + character_sql_to_python_plugin, + simple_sql_to_python_plugin, + sql_to_python_last_resort_plugin, + ] + +def lookup_converter(cursor, field): + for plugin in sql_to_python_plugins: + f = plugin(cursor, field) + if f: + return filter_NULL(f) + return None # this should never happen +
--- a/MySQLdb/cursors.py Fri Feb 27 19:46:55 2009 +0000 +++ b/MySQLdb/cursors.py Sat Feb 28 04:06:44 2009 +0000 @@ -125,8 +125,16 @@ def _do_get_result(self): """Get the result from the last query.""" + from MySQLdb.converters import lookup_converter connection = self._get_db() self._result = self._get_result() + if self._result: + self.sql_to_python = [ + lookup_converter(self, f) + for f in self._result.fields() + ] + else: + self.sql_to_python = [] self.rowcount = connection.affected_rows() self.rownumber = 0 self.description = self._result and self._result.describe() or None @@ -184,6 +192,7 @@ del traceback self.messages.append((exc, value)) self.errorhandler(self, exc, value) + self._executed = query if not self._defer_warnings: self._warning_check() @@ -313,7 +322,14 @@ """Low-level fetch_row wrapper.""" if not self._result: return () - return self._result.fetch_row(size, self._fetch_type) + # unfortunately it is necessary to wrap these generators up as tuples + # as the rows are expected to be subscriptable. + return tuple( + ( + tuple( ( f(x) for f, x in zip(self.sql_to_python, row) ) ) + for row in self._result.fetch_row(size, self._fetch_type) + ) + ) def __iter__(self): return iter(self.fetchone, None)