diff options
Diffstat (limited to 'debug_toolbar/panels/sql.py')
| -rw-r--r-- | debug_toolbar/panels/sql.py | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index 8042269..226778b 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -5,7 +5,10 @@ from copy import copy from django.conf.urls import patterns, url from django.db import connections +from django.http import HttpResponseBadRequest +from django.shortcuts import render from django.utils.translation import ugettext_lazy as _, ungettext_lazy as __ +from django.views.decorators.csrf import csrf_exempt from debug_toolbar.forms import SQLSelectForm from debug_toolbar.panels import DebugPanel @@ -106,7 +109,7 @@ class SQLDebugPanel(DebugPanel): @classmethod def get_urls(cls): - return patterns('debug_toolbar.views', # noqa + return patterns('debug_toolbar.panels.sql', # noqa url(r'^sql_select/$', 'sql_select', name='sql_select'), url(r'^sql_explain/$', 'sql_explain', name='sql_explain'), url(r'^sql_profile/$', 'sql_profile', name='sql_profile'), @@ -208,3 +211,109 @@ class SQLDebugPanel(DebugPanel): 'queries': [q for a, q in self._queries], 'sql_time': self._sql_time, }) + + +@csrf_exempt +def sql_select(request): + """Returns the output of the SQL SELECT statement""" + form = SQLSelectForm(request.POST or None) + + if form.is_valid(): + sql = form.cleaned_data['raw_sql'] + params = form.cleaned_data['params'] + cursor = form.cursor + cursor.execute(sql, params) + headers = [d[0] for d in cursor.description] + result = cursor.fetchall() + cursor.close() + context = { + 'result': result, + 'sql': form.reformat_sql(), + 'duration': form.cleaned_data['duration'], + 'headers': headers, + 'alias': form.cleaned_data['alias'], + } + return render(request, 'debug_toolbar/panels/sql_select.html', context) + return HttpResponseBadRequest('Form errors') + + +@csrf_exempt +def sql_explain(request): + """Returns the output of the SQL EXPLAIN on the given query""" + form = SQLSelectForm(request.POST or None) + + if form.is_valid(): + sql = form.cleaned_data['raw_sql'] + params = form.cleaned_data['params'] + cursor = form.cursor + + conn = form.connection + engine = conn.__class__.__module__.split('.', 1)[0] + + if engine == "sqlite3": + # SQLite's EXPLAIN dumps the low-level opcodes generated for a query; + # EXPLAIN QUERY PLAN dumps a more human-readable summary + # See http://www.sqlite.org/lang_explain.html for details + cursor.execute("EXPLAIN QUERY PLAN %s" % (sql,), params) + elif engine == "psycopg2": + cursor.execute("EXPLAIN ANALYZE %s" % (sql,), params) + else: + cursor.execute("EXPLAIN %s" % (sql,), params) + + headers = [d[0] for d in cursor.description] + result = cursor.fetchall() + cursor.close() + context = { + 'result': result, + 'sql': form.reformat_sql(), + 'duration': form.cleaned_data['duration'], + 'headers': headers, + 'alias': form.cleaned_data['alias'], + } + return render(request, 'debug_toolbar/panels/sql_explain.html', context) + return HttpResponseBadRequest('Form errors') + + +@csrf_exempt +def sql_profile(request): + """Returns the output of running the SQL and getting the profiling statistics""" + form = SQLSelectForm(request.POST or None) + + if form.is_valid(): + sql = form.cleaned_data['raw_sql'] + params = form.cleaned_data['params'] + cursor = form.cursor + result = None + headers = None + result_error = None + try: + 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() + except Exception: + result_error = "Profiling is either not available or not supported by your database." + cursor.close() + context = { + 'result': result, + 'result_error': result_error, + 'sql': form.reformat_sql(), + 'duration': form.cleaned_data['duration'], + 'headers': headers, + 'alias': form.cleaned_data['alias'], + } + return render(request, 'debug_toolbar/panels/sql_profile.html', context) + return HttpResponseBadRequest('Form errors') |
