Commit 3fe3887a authored by Adam Chainz's avatar Adam Chainz Committed by Tim Graham
Browse files

Fixed #25377 -- Changed Count queries to execute COUNT(*) instead of COUNT('*').

parent 4d933ad4
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
Classes to represent the definitions of aggregate functions.
"""
from django.core.exceptions import FieldError
from django.db.models.expressions import Func, Value
from django.db.models.expressions import Func, Star
from django.db.models.fields import FloatField, IntegerField

__all__ = [
@@ -98,7 +98,7 @@ class Count(Aggregate):

    def __init__(self, expression, distinct=False, **extra):
        if expression == '*':
            expression = Value(expression)
            expression = Star()
        super(Count, self).__init__(
            expression, distinct='DISTINCT ' if distinct else '', output_field=IntegerField(), **extra)

+8 −0
Original line number Diff line number Diff line
@@ -593,6 +593,14 @@ class RawSQL(Expression):
        return [self]


class Star(Expression):
    def __repr__(self):
        return "'*'"

    def as_sql(self, compiler, connection):
        return '*', []


class Random(Expression):
    def __init__(self):
        super(Random, self).__init__(output_field=fields.FloatField())
+4 −0
Original line number Diff line number Diff line
@@ -32,3 +32,7 @@ Bugfixes

* Fixed migrations crash on MySQL when adding a text or a blob field with an
  unhashable default (:ticket:`25393`).

* Changed ``Count`` queries to execute ``COUNT(*)`` instead of ``COUNT('*')``
  as versions of Django before 1.8 did (:ticket:`25377`). This may fix a
  performance regression on some databases.
+6 −0
Original line number Diff line number Diff line
@@ -405,6 +405,12 @@ class AggregateTestCase(TestCase):
        vals = Book.objects.aggregate(Count("rating", distinct=True))
        self.assertEqual(vals, {"rating__count": 4})

    def test_count_star(self):
        with self.assertNumQueries(1) as ctx:
            Book.objects.aggregate(n=Count("*"))
        sql = ctx.captured_queries[0]['sql']
        self.assertIn('SELECT COUNT(*) ', sql)

    def test_non_grouped_annotation_not_in_group_by(self):
        """
        An annotation not included in values() before an aggregate should be
+1 −0
Original line number Diff line number Diff line
@@ -878,6 +878,7 @@ class ReprTests(TestCase):
    def test_aggregates(self):
        self.assertEqual(repr(Avg('a')), "Avg(F(a))")
        self.assertEqual(repr(Count('a')), "Count(F(a), distinct=False)")
        self.assertEqual(repr(Count('*')), "Count('*', distinct=False)")
        self.assertEqual(repr(Max('a')), "Max(F(a))")
        self.assertEqual(repr(Min('a')), "Min(F(a))")
        self.assertEqual(repr(StdDev('a')), "StdDev(F(a), sample=False)")
Loading