From 5f51f0524a8cd941ea757a0339978f3589193cbb Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Sun, 19 Aug 2007 22:47:43 +0000 Subject: [PATCH] Refactored get_date_trunc_sql() to DatabaseOperations.date_trunc_sql(). Refs #5106 git-svn-id: http://code.djangoproject.com/svn/django/trunk@5952 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/backends/__init__.py | 8 ++++++ django/db/backends/ado_mssql/base.py | 17 ++++++------ django/db/backends/dummy/base.py | 1 - django/db/backends/mysql/base.py | 27 +++++++++---------- django/db/backends/mysql_old/base.py | 27 +++++++++---------- django/db/backends/oracle/base.py | 19 +++++++------ django/db/backends/postgresql/base.py | 9 +++---- .../db/backends/postgresql_psycopg2/base.py | 9 +++---- django/db/backends/sqlite3/base.py | 12 ++++----- django/db/models/query.py | 5 ++-- 10 files changed, 67 insertions(+), 67 deletions(-) diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 5a9560aac32..68ee950a825 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -60,3 +60,11 @@ class BaseDatabaseOperations(object): extracts a value from the given date field field_name. """ raise NotImplementedError() + + def date_trunc_sql(self, lookup_type, field_name): + """ + Given a lookup_type of 'year', 'month' or 'day', returns the SQL that + truncates the given date field field_name to a DATE object with only + the given specificity. + """ + raise NotImplementedError() diff --git a/django/db/backends/ado_mssql/base.py b/django/db/backends/ado_mssql/base.py index 561cd337a69..2c2d33c87f3 100644 --- a/django/db/backends/ado_mssql/base.py +++ b/django/db/backends/ado_mssql/base.py @@ -52,6 +52,14 @@ class DatabaseOperations(BaseDatabaseOperations): def date_extract_sql(self, lookup_type, field_name): return "DATEPART(%s, %s)" % (lookup_type, field_name) + def date_trunc_sql(self, lookup_type, field_name): + if lookup_type == 'year': + return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name + if lookup_type == 'month': + return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name) + if lookup_type == 'day': + return "Convert(datetime, Convert(varchar(12), %s))" % field_name + class DatabaseWrapper(BaseDatabaseWrapper): ops = DatabaseOperations() @@ -89,15 +97,6 @@ def get_last_insert_id(cursor, table_name, pk_name): cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name)) return cursor.fetchone()[0] -def get_date_trunc_sql(lookup_type, field_name): - # lookup_type is 'year', 'month', 'day' - if lookup_type=='year': - return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name - if lookup_type=='month': - return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name) - if lookup_type=='day': - return "Convert(datetime, Convert(varchar(12), %s))" % field_name - def get_datetime_cast_sql(): return None diff --git a/django/db/backends/dummy/base.py b/django/db/backends/dummy/base.py index 245ab9b0028..a13b62169a7 100644 --- a/django/db/backends/dummy/base.py +++ b/django/db/backends/dummy/base.py @@ -44,7 +44,6 @@ dictfetchone = complain dictfetchmany = complain dictfetchall = complain get_last_insert_id = complain -get_date_trunc_sql = complain get_datetime_cast_sql = complain get_limit_offset_sql = complain get_random_function_sql = complain diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index e257b39bb8f..e426137251f 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -58,6 +58,19 @@ class DatabaseOperations(BaseDatabaseOperations): # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name) + def date_trunc_sql(self, lookup_type, field_name): + fields = ['year', 'month', 'day', 'hour', 'minute', 'second'] + format = ('%%Y-', '%%m', '-%%d', ' %%H:', '%%i', ':%%s') # Use double percents to escape. + format_def = ('0000-', '01', '-01', ' 00:', '00', ':00') + try: + i = fields.index(lookup_type) + 1 + except ValueError: + sql = field_name + else: + format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]]) + sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str) + return sql + class DatabaseWrapper(BaseDatabaseWrapper): ops = DatabaseOperations() @@ -139,20 +152,6 @@ dictfetchall = util.dictfetchall def get_last_insert_id(cursor, table_name, pk_name): return cursor.lastrowid -def get_date_trunc_sql(lookup_type, field_name): - # lookup_type is 'year', 'month', 'day' - fields = ['year', 'month', 'day', 'hour', 'minute', 'second'] - format = ('%%Y-', '%%m', '-%%d', ' %%H:', '%%i', ':%%s') # Use double percents to escape. - format_def = ('0000-', '01', '-01', ' 00:', '00', ':00') - try: - i = fields.index(lookup_type) + 1 - except ValueError: - sql = field_name - else: - format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]]) - sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str) - return sql - def get_datetime_cast_sql(): return None diff --git a/django/db/backends/mysql_old/base.py b/django/db/backends/mysql_old/base.py index 457b6ef777c..579fc01f689 100644 --- a/django/db/backends/mysql_old/base.py +++ b/django/db/backends/mysql_old/base.py @@ -68,6 +68,19 @@ class DatabaseOperations(BaseDatabaseOperations): # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name) + def date_trunc_sql(self, lookup_type, field_name): + fields = ['year', 'month', 'day', 'hour', 'minute', 'second'] + format = ('%%Y-', '%%m', '-%%d', ' %%H:', '%%i', ':%%s') # Use double percents to escape. + format_def = ('0000-', '01', '-01', ' 00:', '00', ':00') + try: + i = fields.index(lookup_type) + 1 + except ValueError: + sql = field_name + else: + format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]]) + sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str) + return sql + class DatabaseWrapper(BaseDatabaseWrapper): ops = DatabaseOperations() @@ -158,20 +171,6 @@ dictfetchall = util.dictfetchall def get_last_insert_id(cursor, table_name, pk_name): return cursor.lastrowid -def get_date_trunc_sql(lookup_type, field_name): - # lookup_type is 'year', 'month', 'day' - fields = ['year', 'month', 'day', 'hour', 'minute', 'second'] - format = ('%%Y-', '%%m', '-%%d', ' %%H:', '%%i', ':%%s') # Use double percents to escape. - format_def = ('0000-', '01', '-01', ' 00:', '00', ':00') - try: - i = fields.index(lookup_type) + 1 - except ValueError: - sql = field_name - else: - format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]]) - sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str) - return sql - def get_datetime_cast_sql(): return None diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py index 7ce5d4485e5..0534d786fba 100644 --- a/django/db/backends/oracle/base.py +++ b/django/db/backends/oracle/base.py @@ -42,6 +42,15 @@ class DatabaseOperations(BaseDatabaseOperations): # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions42a.htm#1017163 return "EXTRACT(%s FROM %s)" % (lookup_type, field_name) + def date_trunc_sql(self, lookup_type, field_name): + # Oracle uses TRUNC() for both dates and numbers. + # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions155a.htm#SQLRF06151 + if lookup_type == 'day': + sql = 'TRUNC(%s)' % field_name + else: + sql = "TRUNC(%s, '%s')" % (field_name, lookup_type) + return sql + class DatabaseWrapper(BaseDatabaseWrapper): ops = DatabaseOperations() @@ -157,16 +166,6 @@ def get_last_insert_id(cursor, table_name, pk_name): cursor.execute('SELECT %s_sq.currval FROM dual' % sq_name) return cursor.fetchone()[0] -def get_date_trunc_sql(lookup_type, field_name): - # lookup_type is 'year', 'month', 'day' - # Oracle uses TRUNC() for both dates and numbers. - # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions155a.htm#SQLRF06151 - if lookup_type == 'day': - sql = 'TRUNC(%s)' % (field_name,) - else: - sql = "TRUNC(%s, '%s')" % (field_name, lookup_type) - return sql - def get_datetime_cast_sql(): return "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS.FF')" diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index fa659b60c0f..5221ebf871e 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -62,6 +62,10 @@ class DatabaseOperations(BaseDatabaseOperations): # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT return "EXTRACT('%s' FROM %s)" % (lookup_type, field_name) + def date_trunc_sql(self, lookup_type, field_name): + # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC + return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name) + class DatabaseWrapper(BaseDatabaseWrapper): ops = DatabaseOperations() @@ -124,11 +128,6 @@ def get_last_insert_id(cursor, table_name, pk_name): cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name)) return cursor.fetchone()[0] -def get_date_trunc_sql(lookup_type, field_name): - # lookup_type is 'year', 'month', 'day' - # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC - return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name) - def get_datetime_cast_sql(): return None diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py index 9bedfbf0774..d5ece11a9cb 100644 --- a/django/db/backends/postgresql_psycopg2/base.py +++ b/django/db/backends/postgresql_psycopg2/base.py @@ -24,6 +24,10 @@ class DatabaseOperations(BaseDatabaseOperations): # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT return "EXTRACT('%s' FROM %s)" % (lookup_type, field_name) + def date_trunc_sql(self, lookup_type, field_name): + # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC + return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name) + class DatabaseWrapper(BaseDatabaseWrapper): ops = DatabaseOperations() @@ -78,11 +82,6 @@ def get_last_insert_id(cursor, table_name, pk_name): cursor.execute("SELECT CURRVAL('\"%s_%s_seq\"')" % (table_name, pk_name)) return cursor.fetchone()[0] -def get_date_trunc_sql(lookup_type, field_name): - # lookup_type is 'year', 'month', 'day' - # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC - return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name) - def get_datetime_cast_sql(): return None diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index c7e84d79464..6caf01dcac4 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -37,9 +37,14 @@ Database.register_adapter(decimal.Decimal, util.rev_typecast_decimal) class DatabaseOperations(BaseDatabaseOperations): def date_extract_sql(self, lookup_type, field_name): # sqlite doesn't support extract, so we fake it with the user-defined - # function _sqlite_extract that's registered in connect(). + # function django_extract that's registered in connect(). return 'django_extract("%s", %s)' % (lookup_type.lower(), field_name) + def date_trunc_sql(self, lookup_type, field_name): + # sqlite doesn't support DATE_TRUNC, so we fake it with a user-defined + # function django_date_trunc that's registered in connect(). + return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name) + class DatabaseWrapper(BaseDatabaseWrapper): ops = DatabaseOperations() @@ -110,11 +115,6 @@ def _sqlite_extract(lookup_type, dt): return None return str(getattr(dt, lookup_type)) -def get_date_trunc_sql(lookup_type, field_name): - # lookup_type is 'year', 'month', 'day' - # sqlite doesn't support DATE_TRUNC, so we fake it as above. - return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name) - def get_datetime_cast_sql(): return None diff --git a/django/db/models/query.py b/django/db/models/query.py index e576540e535..d6ec1e29573 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -647,11 +647,10 @@ class DateQuerySet(QuerySet): if backend.allows_group_by_ordinal: group_by = '1' else: - group_by = backend.get_date_trunc_sql(self._kind, - '%s.%s' % (table_name, field_name)) + group_by = connection.ops.date_trunc_sql(self._kind, '%s.%s' % (table_name, field_name)) sql = 'SELECT %s %s GROUP BY %s ORDER BY 1 %s' % \ - (backend.get_date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table), + (connection.ops.date_trunc_sql(self._kind, '%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(self._field.column))), sql, group_by, self._order) cursor = connection.cursor() cursor.execute(sql, params)