aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debug_toolbar/utils/tracking/db.py42
1 files changed, 33 insertions, 9 deletions
diff --git a/debug_toolbar/utils/tracking/db.py b/debug_toolbar/utils/tracking/db.py
index 7370374..c0789eb 100644
--- a/debug_toolbar/utils/tracking/db.py
+++ b/debug_toolbar/utils/tracking/db.py
@@ -9,18 +9,20 @@ from django.utils import simplejson
from django.utils.encoding import force_unicode, smart_str
from django.utils.hashcompat import sha_constructor
-from debug_toolbar.utils import ms_from_timedelta, tidy_stacktrace, get_template_info, \
- get_stack
+from debug_toolbar.utils import ms_from_timedelta, tidy_stacktrace, \
+ get_template_info, get_stack
from debug_toolbar.utils.compat.db import connections
# TODO:This should be set in the toolbar loader as a default and panels should
# get a copy of the toolbar object with access to its config dictionary
SQL_WARNING_THRESHOLD = getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}) \
.get('SQL_WARNING_THRESHOLD', 500)
+
class SQLQueryTriggered(Exception):
"""Thrown when template panel triggers a query"""
pass
+
class ThreadLocalState(local):
def __init__(self):
self.enabled = True
@@ -34,12 +36,15 @@ class ThreadLocalState(local):
def recording(self, v):
self.enabled = v
+
state = ThreadLocalState()
-recording = state.recording # export function
+recording = state.recording # export function
+
def CursorWrapper(*args, **kwds): # behave like a class
return state.Wrapper(*args, **kwds)
+
class ExceptionCursorWrapper(object):
"""
Wraps a cursor and raises an exception on any operation.
@@ -51,6 +56,7 @@ class ExceptionCursorWrapper(object):
def __getattr__(self, attr):
raise SQLQueryTriggered()
+
class NormalCursorWrapper(object):
"""
Wraps a cursor and logs queries.
@@ -63,6 +69,19 @@ class NormalCursorWrapper(object):
# logger must implement a ``record`` method
self.logger = logger
+ def _quote_expr(self, element):
+ if isinstance(element, basestring):
+ element = element.replace("'", "''")
+ return "'%s'" % element
+ else:
+ return repr(element)
+
+ def _quote_params(self, params):
+ if isinstance(params, dict):
+ return dict((key, self._quote_expr(value))
+ for key, value in params.iteritems())
+ return map(self._quote_expr, params)
+
def execute(self, sql, params=()):
__traceback_hide__ = True
start = datetime.now()
@@ -71,7 +90,8 @@ class NormalCursorWrapper(object):
finally:
stop = datetime.now()
duration = ms_from_timedelta(stop - start)
- enable_stacktraces = getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}) \
+ enable_stacktraces = getattr(settings,
+ 'DEBUG_TOOLBAR_CONFIG', {}) \
.get('ENABLE_STACKTRACES', True)
if enable_stacktraces:
stacktrace = tidy_stacktrace(reversed(get_stack()))
@@ -79,9 +99,11 @@ class NormalCursorWrapper(object):
stacktrace = []
_params = ''
try:
- _params = simplejson.dumps([force_unicode(x, strings_only=True) for x in params])
+ _params = simplejson.dumps(
+ [force_unicode(x, strings_only=True) for x in params]
+ )
except TypeError:
- pass # object not JSON serializable
+ pass # object not JSON serializable
template_info = None
cur_frame = sys._getframe().f_back
@@ -108,11 +130,14 @@ class NormalCursorWrapper(object):
params = {
'engine': engine,
'alias': alias,
- 'sql': self.db.ops.last_executed_query(self.cursor, sql, params),
+ 'sql': self.db.ops.last_executed_query(self.cursor, sql,
+ self._quote_params(params)),
'duration': duration,
'raw_sql': sql,
'params': _params,
- 'hash': sha_constructor(settings.SECRET_KEY + smart_str(sql) + _params).hexdigest(),
+ 'hash': sha_constructor(settings.SECRET_KEY \
+ + smart_str(sql) \
+ + _params).hexdigest(),
'stacktrace': stacktrace,
'start_time': start,
'stop_time': stop,
@@ -129,7 +154,6 @@ class NormalCursorWrapper(object):
'encoding': conn.encoding,
})
-
# We keep `sql` to maintain backwards compatibility
self.logger.record(**params)