Skip to content

Commit ef9cfbb

Browse files
committed
Only elide top-level select lists
If a query has subselects in its WHERE clause, do not elide the select lists in those subselects.
1 parent 3b881fb commit ef9cfbb

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

debug_toolbar/panels/sql/utils.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@
88

99

1010
class ElideSelectListsFilter:
11-
"""sqlparse filter to elide the select list in SELECT ... FROM clauses"""
11+
"""sqlparse filter to elide the select list from top-level SELECT ... FROM clauses,
12+
if present"""
1213

1314
def process(self, stream):
15+
allow_elision = True
1416
for token_type, value in stream:
1517
yield token_type, value
16-
if token_type in T.Keyword and value.upper() == "SELECT":
17-
yield from self.elide_until_from(stream)
18+
if token_type in T.Keyword:
19+
keyword = value.upper()
20+
if allow_elision and keyword == "SELECT":
21+
yield from self.elide_until_from(stream)
22+
allow_elision = keyword in ["EXCEPT", "INTERSECT", "UNION"]
1823

1924
@staticmethod
2025
def elide_until_from(stream):

tests/panels/test_sql.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,44 @@ def test_simplification(self):
510510
self.assertNotIn("\u2022", self.panel._queries[1]["sql"])
511511
self.assertIn("\u2022", self.panel._queries[2]["sql"])
512512

513+
def test_top_level_simplification(self):
514+
"""
515+
Test case to validate that top-level select lists get elided, but other select
516+
lists for subselects do not.
517+
"""
518+
list(User.objects.filter(id__in=User.objects.filter(is_staff=True)))
519+
list(User.objects.filter(id__lt=20).union(User.objects.filter(id__gt=10)))
520+
if connection.vendor != "mysql":
521+
list(
522+
User.objects.filter(id__lt=20).intersection(
523+
User.objects.filter(id__gt=10)
524+
)
525+
)
526+
list(
527+
User.objects.filter(id__lt=20).difference(
528+
User.objects.filter(id__gt=10)
529+
)
530+
)
531+
response = self.panel.process_request(self.request)
532+
self.panel.generate_stats(self.request, response)
533+
if connection.vendor != "mysql":
534+
self.assertEqual(len(self.panel._queries), 4)
535+
else:
536+
self.assertEqual(len(self.panel._queries), 2)
537+
# WHERE ... IN SELECT ... queries should have only one elided select list
538+
self.assertEqual(self.panel._queries[0]["sql"].count("SELECT"), 4)
539+
self.assertEqual(self.panel._queries[0]["sql"].count("\u2022"), 3)
540+
# UNION queries should have two elidid select lists
541+
self.assertEqual(self.panel._queries[1]["sql"].count("SELECT"), 4)
542+
self.assertEqual(self.panel._queries[1]["sql"].count("\u2022"), 6)
543+
if connection.vendor != "mysql":
544+
# INTERSECT queries should have two elidid select lists
545+
self.assertEqual(self.panel._queries[2]["sql"].count("SELECT"), 4)
546+
self.assertEqual(self.panel._queries[2]["sql"].count("\u2022"), 6)
547+
# EXCEPT queries should have two elidid select lists
548+
self.assertEqual(self.panel._queries[3]["sql"].count("SELECT"), 4)
549+
self.assertEqual(self.panel._queries[3]["sql"].count("\u2022"), 6)
550+
513551
@override_settings(
514552
DEBUG=True,
515553
)

0 commit comments

Comments
 (0)