diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 33ec14e4d7..99f8f27ad9 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -398,6 +398,15 @@ class BaseDatabaseOperations(object): # Default to a float return float(value) + def check_aggregate_support(self, aggregate_func): + """Check that the backend supports the provided aggregate + + This is used on specific backends to rule out known aggregates + that are known to have faulty implementations. If the named + aggregate function has a known problem, the backend should + raise NotImplemented. + """ + pass class BaseDatabaseIntrospection(object): """ diff --git a/django/db/backends/postgresql/operations.py b/django/db/backends/postgresql/operations.py index 235210939f..9f221b3822 100644 --- a/django/db/backends/postgresql/operations.py +++ b/django/db/backends/postgresql/operations.py @@ -144,3 +144,14 @@ class DatabaseOperations(BaseDatabaseOperations): def prep_for_iexact_query(self, x): return x + + def check_aggregate_support(self, aggregate): + """Check that the backend fully supports the provided aggregate. + + The implementation of population statistics (STDDEV_POP and VAR_POP) + under Postgres 8.2 - 8.2.4 is known to be faulty. Raise + NotImplementedError if this is the database in use. + """ + if aggregate.sql_function == 'STDDEV_POP' or aggregate.sql_function == 'VAR_POP': + if self.postgres_version[0] == 8 and self.postgres_version[1] == 2 and self.postgres_version[1] <= 4: + raise NotImplementedError('PostgreSQL 8.2 to 8.2.4 is known to have a faulty implementation of %s. Please upgrade your version of PostgreSQL.' % aggregate.sql_function) diff --git a/django/db/models/aggregates.py b/django/db/models/aggregates.py index 1f676253b5..45348a3f75 100644 --- a/django/db/models/aggregates.py +++ b/django/db/models/aggregates.py @@ -41,8 +41,12 @@ class Aggregate(object): * is_summary is a boolean that is set True if the aggregate is a summary value rather than an annotation. """ - aggregate = getattr(query.aggregates_module, self.name) - query.aggregate_select[alias] = aggregate(col, source=source, is_summary=is_summary, **self.extra) + klass = getattr(query.aggregates_module, self.name) + aggregate = klass(col, source=source, is_summary=is_summary, **self.extra) + # Validate that the backend has a fully supported, correct + # implementation of this aggregate + query.connection.ops.check_aggregate_support(aggregate) + query.aggregate_select[alias] = aggregate class Avg(Aggregate): name = 'Avg' diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt index 83f2b1e9d2..69e1a7065b 100644 --- a/docs/ref/databases.txt +++ b/docs/ref/databases.txt @@ -13,6 +13,22 @@ This file describes some of the features that might be relevant to Django usage. Of course, it is not intended as a replacement for server-specific documentation or reference manuals. +PostgreSQL notes +================ + +PostgreSQL 8.2 to 8.2.4 +----------------------- + +The implementation of the population statistics aggregates ``STDDEV_POP`` and +``VAR_POP`` that shipped with PostgreSQL 8.2 to 8.2.4 are `known to be +faulty`_. Users of these releases of PostgreSQL are advised to upgrade to +`Release 8.2.5`_ or later. Django will raise a ``NotImplementedError`` if you +attempt to use the ``StdDev(sample=False)`` or ``Variance(sample=False)`` +aggregate with an database backend falls within the affected release range. + +.. _known to be faulty: http://archives.postgresql.org/pgsql-bugs/2007-07/msg00046.php +.. _Release 8.2.5: http://developer.postgresql.org/pgdocs/postgres/release-8-2-5.html + .. _mysql-notes: MySQL notes