diff options
Diffstat (limited to 'debug_toolbar/utils/tracking/db.py')
| -rw-r--r-- | debug_toolbar/utils/tracking/db.py | 42 |
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) |
