9
9
from django .utils .encoding import force_unicode , smart_str
10
10
from django .utils .hashcompat import sha_constructor
11
11
12
- from debug_toolbar .utils import ms_from_timedelta , tidy_stacktrace , get_template_info , \
13
- get_stack
12
+ from debug_toolbar .utils import ms_from_timedelta , tidy_stacktrace , \
13
+ get_template_info , get_stack
14
14
from debug_toolbar .utils .compat .db import connections
15
15
# TODO:This should be set in the toolbar loader as a default and panels should
16
16
# get a copy of the toolbar object with access to its config dictionary
17
17
SQL_WARNING_THRESHOLD = getattr (settings , 'DEBUG_TOOLBAR_CONFIG' , {}) \
18
18
.get ('SQL_WARNING_THRESHOLD' , 500 )
19
19
20
+
20
21
class SQLQueryTriggered (Exception ):
21
22
"""Thrown when template panel triggers a query"""
22
23
pass
23
24
25
+
24
26
class ThreadLocalState (local ):
25
27
def __init__ (self ):
26
28
self .enabled = True
@@ -34,12 +36,15 @@ def Wrapper(self):
34
36
def recording (self , v ):
35
37
self .enabled = v
36
38
39
+
37
40
state = ThreadLocalState ()
38
- recording = state .recording # export function
41
+ recording = state .recording # export function
42
+
39
43
40
44
def CursorWrapper (* args , ** kwds ): # behave like a class
41
45
return state .Wrapper (* args , ** kwds )
42
46
47
+
43
48
class ExceptionCursorWrapper (object ):
44
49
"""
45
50
Wraps a cursor and raises an exception on any operation.
@@ -51,6 +56,7 @@ def __init__(self, cursor, db, logger):
51
56
def __getattr__ (self , attr ):
52
57
raise SQLQueryTriggered ()
53
58
59
+
54
60
class NormalCursorWrapper (object ):
55
61
"""
56
62
Wraps a cursor and logs queries.
@@ -63,6 +69,19 @@ def __init__(self, cursor, db, logger):
63
69
# logger must implement a ``record`` method
64
70
self .logger = logger
65
71
72
+ def _quote_expr (self , element ):
73
+ if isinstance (element , basestring ):
74
+ element = element .replace ("'" , "''" )
75
+ return "'%s'" % element
76
+ else :
77
+ return repr (element )
78
+
79
+ def _quote_params (self , params ):
80
+ if isinstance (params , dict ):
81
+ return dict ((key , self ._quote_expr (value ))
82
+ for key , value in params .iteritems ())
83
+ return map (self ._quote_expr , params )
84
+
66
85
def execute (self , sql , params = ()):
67
86
__traceback_hide__ = True
68
87
start = datetime .now ()
@@ -71,17 +90,20 @@ def execute(self, sql, params=()):
71
90
finally :
72
91
stop = datetime .now ()
73
92
duration = ms_from_timedelta (stop - start )
74
- enable_stacktraces = getattr (settings , 'DEBUG_TOOLBAR_CONFIG' , {}) \
93
+ enable_stacktraces = getattr (settings ,
94
+ 'DEBUG_TOOLBAR_CONFIG' , {}) \
75
95
.get ('ENABLE_STACKTRACES' , True )
76
96
if enable_stacktraces :
77
97
stacktrace = tidy_stacktrace (reversed (get_stack ()))
78
98
else :
79
99
stacktrace = []
80
100
_params = ''
81
101
try :
82
- _params = simplejson .dumps ([force_unicode (x , strings_only = True ) for x in params ])
102
+ _params = simplejson .dumps (
103
+ [force_unicode (x , strings_only = True ) for x in params ]
104
+ )
83
105
except TypeError :
84
- pass # object not JSON serializable
106
+ pass # object not JSON serializable
85
107
86
108
template_info = None
87
109
cur_frame = sys ._getframe ().f_back
@@ -108,11 +130,14 @@ def execute(self, sql, params=()):
108
130
params = {
109
131
'engine' : engine ,
110
132
'alias' : alias ,
111
- 'sql' : self .db .ops .last_executed_query (self .cursor , sql , params ),
133
+ 'sql' : self .db .ops .last_executed_query (self .cursor , sql ,
134
+ self ._quote_params (params )),
112
135
'duration' : duration ,
113
136
'raw_sql' : sql ,
114
137
'params' : _params ,
115
- 'hash' : sha_constructor (settings .SECRET_KEY + smart_str (sql ) + _params ).hexdigest (),
138
+ 'hash' : sha_constructor (settings .SECRET_KEY \
139
+ + smart_str (sql ) \
140
+ + _params ).hexdigest (),
116
141
'stacktrace' : stacktrace ,
117
142
'start_time' : start ,
118
143
'stop_time' : stop ,
@@ -129,7 +154,6 @@ def execute(self, sql, params=()):
129
154
'encoding' : conn .encoding ,
130
155
})
131
156
132
-
133
157
# We keep `sql` to maintain backwards compatibility
134
158
self .logger .record (** params )
135
159
0 commit comments