diff options
| author | David Cramer | 2012-01-12 17:52:09 -0800 | 
|---|---|---|
| committer | David Cramer | 2012-01-12 17:52:09 -0800 | 
| commit | d346f304018699a04354027719d32616dbaea2d1 (patch) | |
| tree | 904b2690748e882110b79d2851b33aa90b890b5d | |
| parent | 5c55e3c91ed95dba6554ec6328fab533656fe0ab (diff) | |
| parent | d6a3b17b15c8bc9aa251c3cf07e5330c4a2dcdb1 (diff) | |
| download | django-debug-toolbar-d346f304018699a04354027719d32616dbaea2d1.tar.bz2 | |
Merge pull request #224 from Apkawa/master
Add escaping string literal in sql for copy&pasting in dbshell
| -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) | 
