summaryrefslogtreecommitdiff
path: root/django/db/backends
diff options
context:
space:
mode:
Diffstat (limited to 'django/db/backends')
-rw-r--r--django/db/backends/__init__.py70
-rw-r--r--django/db/backends/mysql/base.py19
-rw-r--r--django/db/backends/oracle/base.py30
-rw-r--r--django/db/backends/oracle/query.py9
-rw-r--r--django/db/backends/sqlite3/base.py8
-rw-r--r--django/db/backends/util.py12
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)