Mercurial > p > mysql-python > mysqldb-2
changeset 84:566baac88764 MySQLdb
Ensure NULLs are returned as None by default. Return bad time values unchanged instead of None.
author | Andy Dustman <adustman@users.sourceforge.net> |
---|---|
date | Wed, 07 Sep 2011 20:59:54 -0400 |
parents | e705129ff06f |
children | c16ae20b964d |
files | MySQLdb/converters.py MySQLdb/cursors.py MySQLdb/times.py |
diffstat | 3 files changed, 92 insertions(+), 69 deletions(-) [+] |
line wrap: on
line diff
--- a/MySQLdb/converters.py Tue Aug 31 22:28:13 2010 -0400 +++ b/MySQLdb/converters.py Wed Sep 07 20:59:54 2011 -0400 @@ -9,8 +9,8 @@ from _mysql import NULL from MySQLdb.constants import FIELD_TYPE, FLAG from MySQLdb.times import datetime_to_sql, timedelta_to_sql, \ - timedelta_or_None, datetime_or_None, date_or_None, \ - mysql_timestamp_converter + timedelta_or_orig, datetime_or_orig, date_or_orig, \ + timestamp_or_orig from types import InstanceType import array import datetime @@ -45,6 +45,24 @@ """Convert None to NULL.""" return NULL # duh +def None_if_NULL(func): + if func is None: return func + def _None_if_NULL(value): + if value is None: return value + return func(value) + _None_if_NULL.__name__ = func.__name__+"_or_None_if_NULL" + return _None_if_NULL + + +int_or_None_if_NULL = None_if_NULL(int) +float_or_None_if_NULL = None_if_NULL(float) +Decimal_or_None_if_NULL = None_if_NULL(Decimal) +SET_to_Set_or_None_if_NULL = None_if_NULL(SET_to_Set) +timestamp_or_None_if_NULL = None_if_NULL(timestamp_or_orig) +datetime_or_None_if_NULL = None_if_NULL(datetime_or_orig) +date_or_None_if_NULL = None_if_NULL(date_or_orig) +timedelta_or_None_if_NULL = None_if_NULL(timedelta_or_orig) + def object_to_quoted_sql(connection, obj): """Convert something into a SQL string literal.""" if hasattr(obj, "__unicode__"): @@ -89,21 +107,21 @@ # character sets, etc.). This should always be used as the last # resort. simple_field_decoders = { - FIELD_TYPE.TINY: int, - FIELD_TYPE.SHORT: int, - FIELD_TYPE.LONG: int, - FIELD_TYPE.FLOAT: float, - FIELD_TYPE.DOUBLE: float, - FIELD_TYPE.DECIMAL: Decimal, - FIELD_TYPE.NEWDECIMAL: Decimal, - FIELD_TYPE.LONGLONG: int, - FIELD_TYPE.INT24: int, - FIELD_TYPE.YEAR: int, - FIELD_TYPE.SET: SET_to_Set, - 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.TINY: int_or_None_if_NULL, + FIELD_TYPE.SHORT: int_or_None_if_NULL, + FIELD_TYPE.LONG: int_or_None_if_NULL, + FIELD_TYPE.FLOAT: float_or_None_if_NULL, + FIELD_TYPE.DOUBLE: float_or_None_if_NULL, + FIELD_TYPE.DECIMAL: Decimal_or_None_if_NULL, + FIELD_TYPE.NEWDECIMAL: Decimal_or_None_if_NULL, + FIELD_TYPE.LONGLONG: int_or_None_if_NULL, + FIELD_TYPE.INT24: int_or_None_if_NULL, + FIELD_TYPE.YEAR: int_or_None_if_NULL, + FIELD_TYPE.SET: SET_to_Set_or_None_if_NULL, + FIELD_TYPE.TIMESTAMP: timestamp_or_None_if_NULL, + FIELD_TYPE.DATETIME: datetime_or_None_if_NULL, + FIELD_TYPE.TIME: timedelta_or_None_if_NULL, + FIELD_TYPE.DATE: date_or_None_if_NULL, } # Decoder protocol
--- a/MySQLdb/cursors.py Tue Aug 31 22:28:13 2010 -0400 +++ b/MySQLdb/cursors.py Wed Sep 07 20:59:54 2011 -0400 @@ -194,9 +194,9 @@ self.errorhandler(self, TypeError, msg) except: exc, value, traceback = sys.exc_info() - del traceback self.messages.append((exc, value)) self.errorhandler(self, exc, value) + del traceback if not self._defer_warnings: self._warning_check()
--- a/MySQLdb/times.py Tue Aug 31 22:28:13 2010 -0400 +++ b/MySQLdb/times.py Wed Sep 07 20:59:54 2011 -0400 @@ -2,6 +2,9 @@ times module ------------ +WARNING: The doctests only pass if you're in the right timezone and +daylight savings time setting. XXX + This module provides some help functions for dealing with MySQL data. Most of these you will not have to use directly. @@ -20,7 +23,7 @@ """Convert UNIX ticks into a date instance. >>> DateFromTicks(1172466380) - datetime.date(2007, 2, 25) + datetime.date(2007, 2, 26) >>> DateFromTicks(0) datetime.date(1969, 12, 31) >>> DateFromTicks(2**31-1) @@ -34,7 +37,7 @@ """Convert UNIX ticks into a time instance. >>> TimeFromTicks(1172466380) - datetime.time(23, 6, 20) + datetime.time(0, 6, 20) >>> TimeFromTicks(0) datetime.time(18, 0) >>> TimeFromTicks(2**31-1) @@ -81,20 +84,20 @@ """ return obj.strftime("%Y-%m-%d %H:%M:%S") -def datetime_or_None(obj): +def datetime_or_orig(obj): """Returns a DATETIME or TIMESTAMP column value as a datetime object: - >>> datetime_or_None('2007-02-25 23:06:20') + >>> datetime_or_orig('2007-02-25 23:06:20') datetime.datetime(2007, 2, 25, 23, 6, 20) - >>> datetime_or_None('2007-02-25T23:06:20') + >>> datetime_or_orig('2007-02-25T23:06:20') datetime.datetime(2007, 2, 25, 23, 6, 20) - Illegal values are returned as None: + Illegal values are returned unchanged: - >>> datetime_or_None('2007-02-31T23:06:20') is None - True - >>> datetime_or_None('0000-00-00 00:00:00') is None - True + >>> datetime_or_orig('2007-02-31T23:06:20') + '2007-02-31T23:06:20' + >>> datetime_or_orig('0000-00-00 00:00:00') + '0000-00-00 00:00:00' """ if ' ' in obj: @@ -102,26 +105,26 @@ elif 'T' in obj: sep = 'T' else: - return date_or_None(obj) + return date_or_orig(obj) try: ymd, hms = obj.split(sep, 1) return datetime(*[ int(x) for x in ymd.split('-')+hms.split(':') ]) except ValueError: - return date_or_None(obj) + return obj -def timedelta_or_None(obj): +def timedelta_or_orig(obj): """Returns a TIME column as a timedelta object: - >>> timedelta_or_None('25:06:17') + >>> timedelta_or_orig('25:06:17') datetime.timedelta(1, 3977) - >>> timedelta_or_None('-25:06:17') + >>> timedelta_or_orig('-25:06:17') datetime.timedelta(-2, 83177) - Illegal values are returned as None: + Illegal values are returned unchanged: - >>> timedelta_or_None('random crap') is None - True + >>> timedelta_or_orig('random crap') + 'random crap' Note that MySQL always returns TIME columns as (+|-)HH:MM:SS, but can accept values as (+|-)DD HH:MM:SS. The latter format will not @@ -141,20 +144,20 @@ else: return tdelta except ValueError: - return None + return obj -def time_or_None(obj): +def time_or_orig(obj): """Returns a TIME column as a time object: - >>> time_or_None('15:06:17') + >>> time_or_orig('15:06:17') datetime.time(15, 6, 17) - Illegal values are returned as None: + Illegal values are returned unchanged: - >>> time_or_None('-25:06:17') is None - True - >>> time_or_None('random crap') is None - True + >>> time_or_orig('-25:06:17') + '-25:06:17' + >>> time_or_orig('random crap') + 'random crap' Note that MySQL always returns TIME columns as (+|-)HH:MM:SS, but can accept values as (+|-)DD HH:MM:SS. The latter format will not @@ -171,26 +174,26 @@ return time(hour=int(hour), minute=int(minute), second=int(second), microsecond=int(modf(float(second))[0]*1000000)) except ValueError: - return None + return obj -def date_or_None(obj): +def date_or_orig(obj): """Returns a DATE column as a date object: - >>> date_or_None('2007-02-26') + >>> date_or_orig('2007-02-26') datetime.date(2007, 2, 26) - Illegal values are returned as None: + Illegal values are returned unchanged: - >>> date_or_None('2007-02-31') is None - True - >>> date_or_None('0000-00-00') is None - True + >>> date_or_orig('2007-02-31') + '2007-02-31' + >>> date_or_orig('0000-00-00') + '0000-00-00' """ try: return date(*map(int, obj.split('-', 2))) except ValueError: - return None + return obj def datetime_to_sql(connection, obj): """Format a DateTime object as an ISO timestamp.""" @@ -200,39 +203,41 @@ """Format a timedelta as an SQL literal.""" return connection.string_literal(timedelta_to_str(obj)) -def mysql_timestamp_converter(timestamp): +def timestamp_or_orig(timestamp): """Convert a MySQL TIMESTAMP to a Timestamp object. MySQL >= 4.1 returns TIMESTAMP in the same format as DATETIME: - >>> mysql_timestamp_converter('2007-02-25 22:32:17') + >>> timestamp_or_orig('2007-02-25 22:32:17') datetime.datetime(2007, 2, 25, 22, 32, 17) MySQL < 4.1 uses a big string of numbers: - >>> mysql_timestamp_converter('20070225223217') + >>> timestamp_or_orig('20070225223217') datetime.datetime(2007, 2, 25, 22, 32, 17) - Illegal values are returned as None: + Illegal values are returned unchanged: - >>> mysql_timestamp_converter('2007-02-31 22:32:17') is None - True - >>> mysql_timestamp_converter('00000000000000') is None - True + >>> timestamp_or_orig('2007-02-31 22:32:17') + '2007-02-31 22:32:17' + >>> timestamp_or_orig('00000000000000') + '00000000000000' """ - if timestamp[4] == '-': - return datetime_or_None(timestamp) - timestamp += "0"*(14-len(timestamp)) # padding - year, month, day, hour, minute, second = \ - int(timestamp[:4]), int(timestamp[4:6]), int(timestamp[6:8]), \ - int(timestamp[8:10]), int(timestamp[10:12]), int(timestamp[12:14]) + try: + if timestamp[4] == '-': + return datetime_or_orig(timestamp) + timestamp += "0"*(14-len(timestamp)) # padding + year, month, day, hour, minute, second = \ + int(timestamp[:4]), int(timestamp[4:6]), int(timestamp[6:8]), \ + int(timestamp[8:10]), int(timestamp[10:12]), int(timestamp[12:14]) + except IndexError: + return timestamp try: return datetime(year, month, day, hour, minute, second) except ValueError: - return None + return timestamp if __name__ == "__main__": import doctest doctest.testmod() - \ No newline at end of file