diff options
| author | Alex Gaynor | 2008-10-06 18:33:49 -0400 |
|---|---|---|
| committer | Alex Gaynor | 2008-10-06 18:33:49 -0400 |
| commit | c10e9814d878eb06cba33387f6b5681e47b163fb (patch) | |
| tree | 0e3192b8f3b496fa1a3fa07a51c0f9a3acfd7a50 | |
| parent | 0368d75afbe578951bcded286a3122c5302e3e4d (diff) | |
| parent | a3492e14765e3f898efc26913a8e8c4445a837b4 (diff) | |
| download | django-debug-toolbar-c10e9814d878eb06cba33387f6b5681e47b163fb.tar.bz2 | |
resolved merge conflicts
| -rw-r--r-- | debug_toolbar/templates/debug_toolbar/panels/sql.html | 2 | ||||
| -rw-r--r-- | debug_toolbar/templates/debug_toolbar/panels/sql_profile.html | 26 | ||||
| -rw-r--r-- | debug_toolbar/templates/debug_toolbar/panels/sql_select.html | 30 | ||||
| -rw-r--r-- | debug_toolbar/urls.py | 2 | ||||
| -rw-r--r-- | debug_toolbar/views.py | 66 |
5 files changed, 126 insertions, 0 deletions
diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql.html b/debug_toolbar/templates/debug_toolbar/panels/sql.html index 6a2d077..d35d83e 100644 --- a/debug_toolbar/templates/debug_toolbar/panels/sql.html +++ b/debug_toolbar/templates/debug_toolbar/panels/sql.html @@ -13,7 +13,9 @@ <td>{{ query.time|floatformat:"4" }}</td> <td> {% if query.params %} + <a class="remoteCall" href="/__debug__/sql_select/?sql={{ query.raw_sql|urlencode }}¶ms={{ query.params|urlencode }}&time={{ query.time|floatformat:"4"|urlencode }}&hash={{ query.hash }}">SELECT</a> <a class="remoteCall" href="/__debug__/sql_explain/?sql={{ query.raw_sql|urlencode }}¶ms={{ query.params|urlencode }}&time={{ query.time|floatformat:"4"|urlencode }}&hash={{ query.hash }}">EXPLAIN</a> + <a class="remoteCall" href="/__debug__/sql_profile/?sql={{ query.raw_sql|urlencode }}¶ms={{ query.params|urlencode }}&time={{ query.time|floatformat:"4"|urlencode }}&hash={{ query.hash }}">PROFILE</a> {% endif %} </td> <td class="syntax">{{ query.sql|safe }}</td> diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql_profile.html b/debug_toolbar/templates/debug_toolbar/panels/sql_profile.html new file mode 100644 index 0000000..c1d04ce --- /dev/null +++ b/debug_toolbar/templates/debug_toolbar/panels/sql_profile.html @@ -0,0 +1,26 @@ +<a class="back" href="">« Back</a> +<h3>SQL Profiled</h3> +<dl> + <dt>Executed SQL</dt> + <dd><pre>{{ sql|safe }}</pre></dd> + <dt>Time</dt> + <dd>{{ time }} ms</dd> +</dl> +<table> + <thead> + <tr> + {% for h in headers %} + <th>{{ h|upper }}</th> + {% endfor %} + </tr> + </thead> + <tbody> + {% for row in result %} + <tr class="{% cycle 'odd' 'even' %}"> + {% for column in row %} + <td>{{ column|escape }}</td> + {% endfor %} + </tr> + {% endfor %} + </tbody> +</table> diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql_select.html b/debug_toolbar/templates/debug_toolbar/panels/sql_select.html new file mode 100644 index 0000000..73109ef --- /dev/null +++ b/debug_toolbar/templates/debug_toolbar/panels/sql_select.html @@ -0,0 +1,30 @@ +<a class="back" href="">« Back</a> +<h3>SQL Selected</h3> +<dl> + <dt>Executed SQL</dt> + <dd><pre>{{ sql|safe }}</pre></dd> + <dt>Time</dt> + <dd>{{ time }} ms</dd> +</dl> +{% if result %} +<table> + <thead> + <tr> + {% for h in headers %} + <th>{{ h|upper }}</th> + {% endfor %} + </tr> + </thead> + <tbody> + {% for row in result %} + <tr class="{% cycle 'odd' 'even' %}"> + {% for column in row %} + <td>{{ column|escape }}</td> + {% endfor %} + </tr> + {% endfor %} + </tbody> +</table> +{% else %} + <p>Empty set</p> +{% endif %} diff --git a/debug_toolbar/urls.py b/debug_toolbar/urls.py index e0e4b7a..53a426b 100644 --- a/debug_toolbar/urls.py +++ b/debug_toolbar/urls.py @@ -9,5 +9,7 @@ from django.conf import settings urlpatterns = patterns('', url(r'^__debug__/m/(.*)$', 'debug_toolbar.views.debug_media'), + url(r'^__debug__/sql_select/$', 'debug_toolbar.views.sql_select', name='sql_select'), url(r'^__debug__/sql_explain/$', 'debug_toolbar.views.sql_explain', name='sql_explain'), + url(r'^__debug__/sql_profile/$', 'debug_toolbar.views.sql_profile', name='sql_profile'), ) diff --git a/debug_toolbar/views.py b/debug_toolbar/views.py index b67a70b..8af879f 100644 --- a/debug_toolbar/views.py +++ b/debug_toolbar/views.py @@ -20,6 +20,37 @@ def debug_media(request, path): root = os.path.join(parent, 'media') return django.views.static.serve(request, path, root) +def sql_select(request): + """ + Returns the output of the SQL SELECT statement. + + Expected GET variables: + sql: urlencoded sql with positional arguments + params: JSON encoded parameter values + time: time for SQL to execute passed in from toolbar just for redisplay + hash: the hash of (secret + sql + params) for tamper checking + """ + from debug_toolbar.panels.sql import reformat_sql + sql = request.GET.get('sql', '') + params = request.GET.get('params', '') + hash = sha_constructor(settings.SECRET_KEY + sql + params).hexdigest() + if hash != request.GET.get('hash', ''): + return HttpResponse('<h3>Tamper alert</h3>') # SQL Tampering alert + if sql.lower().startswith('select'): + params = simplejson.loads(params) + cursor = connection.cursor() + cursor.execute(sql, params) + headers = [d[0] for d in cursor.description] + result = cursor.fetchall() + cursor.close() + context = { + 'result': result, + 'sql': reformat_sql(cursor.db.ops.last_executed_query(cursor, sql, params)), + 'time': request.GET.get('time', 0.0), + 'headers': headers, + } + return render_to_response('debug_toolbar/panels/sql_select.html', context) + def sql_explain(request): """ Returns the output of the SQL EXPLAIN on the given query. @@ -50,3 +81,38 @@ def sql_explain(request): 'headers': headers, } return render_to_response('debug_toolbar/panels/sql_explain.html', context) + +def sql_profile(request): + """ + Returns the output of running the SQL and getting the profiling statistics. + + Expected GET variables: + sql: urlencoded sql with positional arguments + params: JSON encoded parameter values + time: time for SQL to execute passed in from toolbar just for redisplay + hash: the hash of (secret + sql + params) for tamper checking + """ + from debug_toolbar.panels.sql import reformat_sql + sql = request.GET.get('sql', '') + params = request.GET.get('params', '') + hash = sha_constructor(settings.SECRET_KEY + sql + params).hexdigest() + if hash != request.GET.get('hash', ''): + return HttpResponse('<h3>Tamper alert</h3>') # SQL Tampering alert + if sql.lower().startswith('select'): + params = simplejson.loads(params) + cursor = connection.cursor() + cursor.execute("SET PROFILING=1") # Enable profiling + cursor.execute(sql, params) # Execute SELECT + cursor.execute("SET PROFILING=0") # Disable profiling + # The Query ID should always be 1 here but I'll subselect to get the last one just in case... + cursor.execute("SELECT * FROM information_schema.profiling WHERE query_id=(SELECT query_id FROM information_schema.profiling ORDER BY query_id DESC LIMIT 1)") + headers = [d[0] for d in cursor.description] + result = cursor.fetchall() + cursor.close() + context = { + 'result': result, + 'sql': reformat_sql(cursor.db.ops.last_executed_query(cursor, sql, params)), + 'time': request.GET.get('time', 0.0), + 'headers': headers, + } + return render_to_response('debug_toolbar/panels/sql_explain.html', context) |
