Skip to content

Commit 5aff6ee

Browse files
committed
SQL injection now happens without interfering with the underlying db.queries objects (and no longer requires DEBUG to be set)
1 parent 4d69dbe commit 5aff6ee

File tree

1 file changed

+36
-25
lines changed

1 file changed

+36
-25
lines changed

debug_toolbar/panels/sql.py

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from datetime import datetime
2-
import itertools
32
import os
43
import re
54
import sys
@@ -25,6 +24,7 @@
2524
from django.utils.safestring import mark_safe
2625
from django.utils.translation import ugettext_lazy as _, ungettext_lazy as __
2726

27+
from debug_toolbar.middleware import DebugToolbarMiddleware
2828
from debug_toolbar.panels import DebugPanel
2929
from debug_toolbar.utils import sqlparse
3030

@@ -89,15 +89,21 @@ def get_template_info(source, context_lines=3):
8989
'context': context,
9090
}
9191

92-
class DatabaseStatTracker(util.CursorDebugWrapper):
92+
def inject_sql_tracker(cls):
9393
"""
94-
Replacement for CursorDebugWrapper which stores additional information
95-
in `connection.queries`.
94+
Injects a replacement execute method which records queries within the SQLPanel.
9695
"""
96+
if getattr(cls.execute, 'is_tracked', False):
97+
return
9798
def execute(self, sql, params=()):
99+
djdt = DebugToolbarMiddleware.get_current()
100+
if not djdt:
101+
return cls.execute.__wraps(self, sql, params)
102+
103+
panel = djdt.get_panel(SQLDebugPanel)
98104
start = datetime.now()
99105
try:
100-
return self.cursor.execute(sql, params)
106+
return cls.execute.__wraps(self, sql, params)
101107
finally:
102108
stop = datetime.now()
103109
duration = ms_from_timedelta(stop - start)
@@ -123,9 +129,9 @@ def execute(self, sql, params=()):
123129
del cur_frame
124130

125131
# We keep `sql` to maintain backwards compatibility
126-
self.db.queries.append({
132+
panel.record(**{
133+
'alias': getattr(self, 'alias', 'default'),
127134
'sql': self.db.ops.last_executed_query(self.cursor, sql, params),
128-
'time': duration * 1000,
129135
'duration': duration,
130136
'raw_sql': sql,
131137
'params': _params,
@@ -137,7 +143,13 @@ def execute(self, sql, params=()):
137143
'is_select': sql.lower().strip().startswith('select'),
138144
'template_info': template_info,
139145
})
140-
util.CursorDebugWrapper = DatabaseStatTracker
146+
execute.is_tracked = True
147+
execute.__wraps = cls.execute
148+
149+
cls.execute = execute
150+
151+
inject_sql_tracker(util.CursorWrapper)
152+
inject_sql_tracker(util.CursorDebugWrapper)
141153

142154
class SQLDebugPanel(DebugPanel):
143155
"""
@@ -151,32 +163,31 @@ def __init__(self, *args, **kwargs):
151163
super(self.__class__, self).__init__(*args, **kwargs)
152164
self._offset = dict((k, len(connections[k].queries)) for k in connections)
153165
self._sql_time = 0
166+
self._num_queries = 0
154167
self._queries = []
155168
self._databases = {}
169+
170+
def record(self, alias, **kwargs):
171+
self._queries.append((alias, kwargs))
172+
if alias not in self._databases:
173+
self._databases[alias] = {
174+
'time_spent': kwargs['duration'],
175+
'num_queries': 1,
176+
}
177+
else:
178+
self._databases[alias]['time_spent'] += kwargs['duration']
179+
self._databases[alias]['num_queries'] += 1
180+
self._sql_time += kwargs['duration']
181+
self._num_queries += 1
156182

157183
def nav_title(self):
158184
return _('SQL')
159185

160186
def nav_subtitle(self):
161-
self._queries = []
162-
self._databases = {}
163-
for alias in connections:
164-
db_queries = connections[alias].queries[self._offset[alias]:]
165-
num_queries = len(db_queries)
166-
if num_queries:
167-
self._databases[alias] = {
168-
'time_spent': sum(q['duration'] for q in db_queries),
169-
'queries': num_queries,
170-
}
171-
self._queries.extend([(alias, q) for q in db_queries])
172-
173-
self._queries.sort(key=lambda x: x[1]['start_time'])
174-
self._sql_time = sum([d['time_spent'] for d in self._databases.itervalues()])
175-
num_queries = len(self._queries)
176187
# TODO l10n: use ngettext
177188
return "%d %s in %.2fms" % (
178-
num_queries,
179-
(num_queries == 1) and 'query' or 'queries',
189+
self._num_queries,
190+
(self._num_queries == 1) and 'query' or 'queries',
180191
self._sql_time
181192
)
182193

0 commit comments

Comments
 (0)