diff options
Diffstat (limited to 'django/db/backends')
-rw-r--r-- | django/db/backends/__init__.py | 70 | ||||
-rw-r--r-- | django/db/backends/mysql/base.py | 19 | ||||
-rw-r--r-- | django/db/backends/oracle/base.py | 30 | ||||
-rw-r--r-- | django/db/backends/oracle/query.py | 9 | ||||
-rw-r--r-- | django/db/backends/sqlite3/base.py | 8 | ||||
-rw-r--r-- | django/db/backends/util.py | 12 |
6 files changed, 128 insertions, 20 deletions
diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 899a779673..d65eacd042 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -5,6 +5,9 @@ except ImportError: # Import copy of _thread_local.py from Python 2.4 from django.utils._threading_local import local +from django.db.backends import util +from django.utils import datetime_safe + class BaseDatabaseWrapper(local): """ Represents a database connection. @@ -36,12 +39,13 @@ class BaseDatabaseWrapper(local): return cursor def make_debug_cursor(self, cursor): - from django.db.backends import util return util.CursorDebugWrapper(cursor, self) class BaseDatabaseFeatures(object): allows_group_by_ordinal = True inline_fk_references = True + # True if django.db.backend.utils.typecast_timestamp is used on values + # returned from dates() calls. needs_datetime_string_cast = True supports_constraints = True supports_tablespaces = False @@ -49,10 +53,7 @@ class BaseDatabaseFeatures(object): uses_custom_query_class = False empty_fetchmany_value = [] update_can_self_select = True - supports_usecs = True - time_field_needs_date = False interprets_empty_strings_as_nulls = False - date_field_supports_time_value = True can_use_chunked_reads = True class BaseDatabaseOperations(object): @@ -263,3 +264,64 @@ class BaseDatabaseOperations(object): """Prepares a value for use in a LIKE query.""" from django.utils.encoding import smart_unicode return smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_") + + def value_to_db_date(self, value): + """ + Transform a date value to an object compatible with what is expected + by the backend driver for date columns. + """ + if value is None: + return None + return datetime_safe.new_date(value).strftime('%Y-%m-%d') + + def value_to_db_datetime(self, value): + """ + Transform a datetime value to an object compatible with what is expected + by the backend driver for datetime columns. + """ + if value is None: + return None + return unicode(value) + + def value_to_db_time(self, value): + """ + Transform a datetime value to an object compatible with what is expected + by the backend driver for time columns. + """ + if value is None: + return None + return unicode(value) + + def value_to_db_decimal(self, value, max_digits, decimal_places): + """ + Transform a decimal.Decimal value to an object compatible with what is + expected by the backend driver for decimal (numeric) columns. + """ + if value is None: + return None + return util.format_number(value, max_digits, decimal_places) + + def year_lookup_bounds(self, value): + """ + Returns a two-elements list with the lower and upper bound to be used + with a BETWEEN operator to query a field value using a year lookup + + `value` is an int, containing the looked-up year. + """ + first = '%s-01-01 00:00:00' + second = '%s-12-31 23:59:59.999999' + return [first % value, second % value] + + def year_lookup_bounds_for_date_field(self, value): + """ + Returns a two-elements list with the lower and upper bound to be used + with a BETWEEN operator to query a DateField value using a year lookup + + `value` is an int, containing the looked-up year. + + By default, it just calls `self.year_lookup_bounds`. Some backends need + this hook because on their DB date fields can't be compared to values + which include a time part. + """ + return self.year_lookup_bounds(value) + diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index 74138a7b11..3b8d897925 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -63,7 +63,6 @@ class DatabaseFeatures(BaseDatabaseFeatures): inline_fk_references = False empty_fetchmany_value = () update_can_self_select = False - supports_usecs = False class DatabaseOperations(BaseDatabaseOperations): def date_extract_sql(self, lookup_type, field_name): @@ -124,6 +123,24 @@ class DatabaseOperations(BaseDatabaseOperations): else: return [] + def value_to_db_datetime(self, value): + # MySQL doesn't support microseconds + if value is None: + return None + return unicode(value.replace(microsecond=0)) + + def value_to_db_time(self, value): + # MySQL doesn't support microseconds + if value is None: + return None + return unicode(value.replace(microsecond=0)) + + def year_lookup_bounds(self, value): + # Again, no microseconds + first = '%s-01-01 00:00:00' + second = '%s-12-31 23:59:59.99' + return [first % value, second % value] + class DatabaseWrapper(BaseDatabaseWrapper): features = DatabaseFeatures() ops = DatabaseOperations() diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index a41084bca3..bdb73b1864 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -5,10 +5,11 @@ Requires cx_Oracle: http://www.python.net/crew/atuining/cx_Oracle/ """ import os +import datetime +import time from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util from django.db.backends.oracle import query -from django.utils.datastructures import SortedDict from django.utils.encoding import smart_str, force_unicode # Oracle takes client-side character set encoding from the environment. @@ -29,9 +30,7 @@ class DatabaseFeatures(BaseDatabaseFeatures): supports_tablespaces = True uses_case_insensitive_names = True uses_custom_query_class = True - time_field_needs_date = True interprets_empty_strings_as_nulls = True - date_field_supports_time_value = False class DatabaseOperations(BaseDatabaseOperations): def autoinc_sql(self, table, column): @@ -181,6 +180,21 @@ class DatabaseOperations(BaseDatabaseOperations): def tablespace_sql(self, tablespace, inline=False): return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), self.quote_name(tablespace)) + def value_to_db_time(self, value): + if value is None: + return None + if isinstance(value, basestring): + return datetime.datetime(*(time.strptime(value, '%H:%M:%S')[:6])) + return datetime.datetime(1900, 1, 1, value.hour, value.minute, + value.second, value.microsecond) + + def year_lookup_bounds_for_date_field(self, value): + first = '%s-01-01' + second = '%s-12-31' + return [first % value, second % value] + + + class DatabaseWrapper(BaseDatabaseWrapper): features = DatabaseFeatures() ops = DatabaseOperations() @@ -245,10 +259,10 @@ class DatabaseWrapper(BaseDatabaseWrapper): class OracleParam(object): """ - Wrapper object for formatting parameters for Oracle. If the string - representation of the value is large enough (greater than 4000 characters) + Wrapper object for formatting parameters for Oracle. If the string + representation of the value is large enough (greater than 4000 characters) the input size needs to be set as NCLOB. Alternatively, if the parameter has - an `input_size` attribute, then the value of the `input_size` attribute will + an `input_size` attribute, then the value of the `input_size` attribute will be used instead. Otherwise, no input size will be set for the parameter when executing the query. """ @@ -282,7 +296,7 @@ class FormatStylePlaceholderCursor(Database.Cursor): return result else: return tuple([OracleParam(p, self.charset, True) for p in params]) - + def _guess_input_sizes(self, params_list): if isinstance(params_list[0], dict): sizes = {} @@ -303,7 +317,7 @@ class FormatStylePlaceholderCursor(Database.Cursor): return dict([(k, p.smart_str) for k, p in params.iteritems()]) else: return [p.smart_str for p in params] - + def execute(self, query, params=None): if params is None: params = [] diff --git a/django/db/backends/oracle/query.py b/django/db/backends/oracle/query.py index 7e50c7b5db..49e1c4131c 100644 --- a/django/db/backends/oracle/query.py +++ b/django/db/backends/oracle/query.py @@ -87,9 +87,11 @@ def query_class(QueryClass, Database): If 'with_limits' is False, any limit/offset information is not included in the query. """ + # The `do_offset` flag indicates whether we need to construct # the SQL needed to use limit/offset w/Oracle. - do_offset = with_limits and (self.high_mark or self.low_mark) + do_offset = with_limits and (self.high_mark is not None + or self.low_mark) # If no offsets, just return the result of the base class # `as_sql`. @@ -117,7 +119,7 @@ def query_class(QueryClass, Database): # Getting the selection SQL and the params, which has the `rn` # extra selection SQL. self.extra_select['rn'] = 'ROW_NUMBER() OVER (ORDER BY %s )' % rn_orderby - sql, params= super(OracleQuery, self).as_sql(with_limits=False, + sql, params = super(OracleQuery, self).as_sql(with_limits=False, with_col_aliases=True) # Constructing the result SQL, using the initial select SQL @@ -126,7 +128,7 @@ def query_class(QueryClass, Database): # Place WHERE condition on `rn` for the desired range. result.append('WHERE rn > %d' % self.low_mark) - if self.high_mark: + if self.high_mark is not None: result.append('AND rn <= %d' % self.high_mark) # Returning the SQL w/params. @@ -148,4 +150,3 @@ def query_class(QueryClass, Database): _classes[QueryClass] = OracleQuery return OracleQuery - diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index 48d9ad4c4b..71be86f00b 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -84,6 +84,12 @@ class DatabaseOperations(BaseDatabaseOperations): # sql_flush() implementations). Just return SQL at this point return sql + def year_lookup_bounds(self, value): + first = '%s-01-01' + second = '%s-12-31 23:59:59.999999' + return [first % value, second % value] + + class DatabaseWrapper(BaseDatabaseWrapper): features = DatabaseFeatures() ops = DatabaseOperations() @@ -159,7 +165,7 @@ def _sqlite_extract(lookup_type, dt): dt = util.typecast_timestamp(dt) except (ValueError, TypeError): return None - return str(getattr(dt, lookup_type)) + return getattr(dt, lookup_type) def _sqlite_date_trunc(lookup_type, dt): try: diff --git a/django/db/backends/util.py b/django/db/backends/util.py index 367072879e..7228b4046b 100644 --- a/django/db/backends/util.py +++ b/django/db/backends/util.py @@ -1,7 +1,8 @@ import datetime -import md5 from time import time +from django.utils.hashcompat import md5_constructor + try: import decimal except ImportError: @@ -114,6 +115,13 @@ def truncate_name(name, length=None): if length is None or len(name) <= length: return name - hash = md5.md5(name).hexdigest()[:4] + hash = md5_constructor(name).hexdigest()[:4] return '%s%s' % (name[:length-4], hash) + +def format_number(value, max_digits, decimal_places): + """ + Formats a number into a string with the requisite number of digits and + decimal places. + """ + return u"%.*f" % (decimal_places, value) |