aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debug_toolbar/panels/sql.py36
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/sql.html10
-rw-r--r--debug_toolbar/utils/compat/db.py9
-rw-r--r--debug_toolbar/utils/tracking/db.py24
-rw-r--r--example/example.dbbin55296 -> 55296 bytes
5 files changed, 69 insertions, 10 deletions
diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py
index ba83455..344f5d6 100644
--- a/debug_toolbar/panels/sql.py
+++ b/debug_toolbar/panels/sql.py
@@ -1,6 +1,5 @@
import re
-from django.conf import settings
from django.db.backends import BaseDatabaseWrapper
from django.template.loader import render_to_string
from django.utils.html import escape
@@ -26,6 +25,36 @@ def cursor(func, self):
return CursorWrapper(result, self, logger=logger)
+def get_isolation_level_display(engine, level):
+ if engine == 'psycopg2':
+ import psycopg2.extensions
+ choices = {
+ psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT: 'Autocommit',
+ psycopg2.extensions.ISOLATION_LEVEL_READ_UNCOMMITTED: 'Read uncommitted',
+ psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED: 'Read committed',
+ psycopg2.extensions.ISOLATION_LEVEL_REPEATABLE_READ: 'Repeatable read',
+ psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE: 'Serializable',
+ }
+ else:
+ raise ValueError(engine)
+
+ return choices.get(level)
+
+def get_transaction_status_display(engine, level):
+ if engine == 'psycopg2':
+ import psycopg2.extensions
+ choices = {
+ psycopg2.extensions.TRANSACTION_STATUS_IDLE: 'Idle',
+ psycopg2.extensions.TRANSACTION_STATUS_ACTIVE: 'Active',
+ psycopg2.extensions.TRANSACTION_STATUS_INTRANS: 'In transaction',
+ psycopg2.extensions.TRANSACTION_STATUS_INERROR: 'In error',
+ psycopg2.extensions.TRANSACTION_STATUS_UNKNOWN: 'Unknown',
+ }
+ else:
+ raise ValueError(engine)
+
+ return choices.get(level)
+
class SQLDebugPanel(DebugPanel):
"""
Panel that displays information about the SQL queries run while processing
@@ -102,6 +131,10 @@ class SQLDebugPanel(DebugPanel):
for alias, query in self._queries:
query['alias'] = alias
+ if 'iso_level' in query:
+ query['iso_level'] = get_isolation_level_display(query['engine'], query['iso_level'])
+ if 'trans_status' in query:
+ query['trans_status'] = get_transaction_status_display(query['engine'], query['trans_status'])
query['sql'] = reformat_sql(query['sql'])
query['rgb_color'] = self._databases[alias]['rgb_color']
try:
@@ -123,7 +156,6 @@ class SQLDebugPanel(DebugPanel):
'databases': sorted(self._databases.items(), key=lambda x: -x[1]['time_spent']),
'queries': [q for a, q in self._queries],
'sql_time': self._sql_time,
- 'is_mysql': settings.DATABASE_ENGINE == 'mysql',
})
return render_to_string('debug_toolbar/panels/sql.html', context)
diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql.html b/debug_toolbar/templates/debug_toolbar/panels/sql.html
index bec97a4..436f3ce 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/sql.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/sql.html
@@ -44,9 +44,9 @@
{% if query.is_select %}
<a class="remoteCall" href="/__debug__/sql_select/?sql={{ query.raw_sql|urlencode }}&amp;params={{ query.params|urlencode }}&amp;duration={{ query.duration|floatformat:"2"|urlencode }}&amp;hash={{ query.hash }}">Sel</a>
<a class="remoteCall" href="/__debug__/sql_explain/?sql={{ query.raw_sql|urlencode }}&amp;params={{ query.params|urlencode }}&amp;duration={{ query.duration|floatformat:"2"|urlencode }}&amp;hash={{ query.hash }}">Expl</a>
- {% if is_mysql %}
+ {% ifequal query.engine 'mysql' %}
<a class="remoteCall" href="/__debug__/sql_profile/?sql={{ query.raw_sql|urlencode }}&amp;params={{ query.params|urlencode }}&amp;duration={{ query.duration|floatformat:"2"|urlencode }}&amp;hash={{ query.hash }}">Prof</a>
- {% endif %}
+ {% endifequal %}
{% endif %}
{% endif %}
</td>
@@ -56,6 +56,12 @@
<td colspan="4">
<div class="djSQLDetailsDiv">
<p><strong>Connection:</strong> {{ query.alias }}</p>
+ {% if query.iso_level %}
+ <p><strong>Isolation Level:</strong> {{ query.iso_level }}</p>
+ {% endif %}
+ {% if query.trans_status %}
+ <p><strong>Transaction Status:</strong> {{ query.trans_status }}</p>
+ {% endif %}
{% if query.stacktrace %}
<pre>{{ query.stacktrace }}</pre>
{% endif %}
diff --git a/debug_toolbar/utils/compat/db.py b/debug_toolbar/utils/compat/db.py
index f3b37e6..4273d9e 100644
--- a/debug_toolbar/utils/compat/db.py
+++ b/debug_toolbar/utils/compat/db.py
@@ -1,6 +1,13 @@
+from django.conf import settings
try:
from django.db import connections
+ dbconf = settings.DATABASES
except ImportError:
# Compat with < Django 1.2
from django.db import connection
- connections = {'default': connection} \ No newline at end of file
+ connections = {'default': connection}
+ dbconf = {
+ 'default': {
+ 'ENGINE': settings.DATABASE_ENGINE,
+ }
+ } \ No newline at end of file
diff --git a/debug_toolbar/utils/tracking/db.py b/debug_toolbar/utils/tracking/db.py
index 4c9ee53..de84785 100644
--- a/debug_toolbar/utils/tracking/db.py
+++ b/debug_toolbar/utils/tracking/db.py
@@ -10,7 +10,7 @@ from django.utils.encoding import force_unicode
from django.utils.hashcompat import sha_constructor
from debug_toolbar.utils import ms_from_timedelta, tidy_stacktrace, get_template_info
-
+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', {}) \
@@ -29,6 +29,9 @@ class CursorWrapper(object):
self.logger = logger
def execute(self, sql, params=()):
+ alias = getattr(self, 'alias', 'default')
+ # HACK: avoid imports
+ engine = connections[alias].connection.__class__.__module__.split('.', 1)[0]
start = datetime.now()
try:
return self.cursor.execute(sql, params)
@@ -56,9 +59,9 @@ class CursorWrapper(object):
pass
del cur_frame
- # We keep `sql` to maintain backwards compatibility
- self.logger.record(**{
- 'alias': getattr(self, 'alias', 'default'),
+ params = {
+ 'engine': engine,
+ 'alias': alias,
'sql': self.db.ops.last_executed_query(self.cursor, sql, params),
'duration': duration,
'raw_sql': sql,
@@ -70,7 +73,18 @@ class CursorWrapper(object):
'is_slow': (duration > SQL_WARNING_THRESHOLD),
'is_select': sql.lower().strip().startswith('select'),
'template_info': template_info,
- })
+ }
+
+ if engine == 'psycopg2':
+ conn = connections[alias].connection
+ params.update({
+ 'trans_status': conn.get_transaction_status(),
+ 'iso_level': conn.isolation_level,
+ 'encoding': conn.encoding,
+ })
+
+ # We keep `sql` to maintain backwards compatibility
+ self.logger.record(**params)
def executemany(self, sql, param_list):
return self.cursor.executemany(sql, param_list)
diff --git a/example/example.db b/example/example.db
index 3ca0f39..c607f31 100644
--- a/example/example.db
+++ b/example/example.db
Binary files differ