[1.8.x] Fixed #25377 -- Changed Count queries to execute COUNT(*) instead of COUNT('*').
Backport of 3fe3887a2e
from master
This commit is contained in:
parent
69017bade0
commit
3c2c74f58f
|
@ -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__ = [
|
||||
|
@ -90,7 +90,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)
|
||||
|
||||
|
|
|
@ -584,6 +584,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())
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -306,6 +306,12 @@ class BaseAggregateTestCase(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_fkey_aggregate(self):
|
||||
explicit = list(Author.objects.annotate(Count('book__id')))
|
||||
implicit = list(Author.objects.annotate(Count('book')))
|
||||
|
|
|
@ -877,6 +877,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)")
|
||||
|
|
|
@ -63,25 +63,25 @@ class TestDebugSQL(unittest.TestCase):
|
|||
|
||||
if six.PY3:
|
||||
expected_outputs = [
|
||||
('''QUERY = 'SELECT COUNT(%s) AS "__count" '''
|
||||
('''QUERY = 'SELECT COUNT(*) AS "__count" '''
|
||||
'''FROM "test_runner_person" WHERE '''
|
||||
'''"test_runner_person"."first_name" = %s' '''
|
||||
'''- PARAMS = ('*', 'error');'''),
|
||||
('''QUERY = 'SELECT COUNT(%s) AS "__count" '''
|
||||
'''- PARAMS = ('error',);'''),
|
||||
('''QUERY = 'SELECT COUNT(*) AS "__count" '''
|
||||
'''FROM "test_runner_person" WHERE '''
|
||||
'''"test_runner_person"."first_name" = %s' '''
|
||||
'''- PARAMS = ('*', 'fail');'''),
|
||||
'''- PARAMS = ('fail',);'''),
|
||||
]
|
||||
else:
|
||||
expected_outputs = [
|
||||
('''QUERY = u'SELECT COUNT(%s) AS "__count" '''
|
||||
('''QUERY = u'SELECT COUNT(*) AS "__count" '''
|
||||
'''FROM "test_runner_person" WHERE '''
|
||||
'''"test_runner_person"."first_name" = %s' '''
|
||||
'''- PARAMS = (u'*', u'error');'''),
|
||||
('''QUERY = u'SELECT COUNT(%s) AS "__count" '''
|
||||
'''- PARAMS = (u'error',);'''),
|
||||
('''QUERY = u'SELECT COUNT(*) AS "__count" '''
|
||||
'''FROM "test_runner_person" WHERE '''
|
||||
'''"test_runner_person"."first_name" = %s' '''
|
||||
'''- PARAMS = (u'*', u'fail');'''),
|
||||
'''- PARAMS = (u'fail',);'''),
|
||||
]
|
||||
|
||||
verbose_expected_outputs = [
|
||||
|
@ -94,15 +94,15 @@ class TestDebugSQL(unittest.TestCase):
|
|||
]
|
||||
if six.PY3:
|
||||
verbose_expected_outputs += [
|
||||
('''QUERY = 'SELECT COUNT(%s) AS "__count" '''
|
||||
('''QUERY = 'SELECT COUNT(*) AS "__count" '''
|
||||
'''FROM "test_runner_person" WHERE '''
|
||||
'''"test_runner_person"."first_name" = %s' '''
|
||||
'''- PARAMS = ('*', 'pass');'''),
|
||||
'''- PARAMS = ('pass',);'''),
|
||||
]
|
||||
else:
|
||||
verbose_expected_outputs += [
|
||||
('''QUERY = u'SELECT COUNT(%s) AS "__count" '''
|
||||
('''QUERY = u'SELECT COUNT(*) AS "__count" '''
|
||||
'''FROM "test_runner_person" WHERE '''
|
||||
'''"test_runner_person"."first_name" = %s' '''
|
||||
'''- PARAMS = (u'*', u'pass');'''),
|
||||
'''- PARAMS = (u'pass',);'''),
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue