From e806603a6e4ac3d488a0cadb1e962507a6f76fc1 Mon Sep 17 00:00:00 2001 From: Anssi Kääriäinen Date: Thu, 5 Jul 2012 14:06:21 +0300 Subject: Fixed issue #230 -- Avoid queries in aborted transactions On PostgreSQL when the transaction is in aborted status, checking connection.isolation_level will result in an error. --- debug_toolbar/utils/tracking/db.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/debug_toolbar/utils/tracking/db.py b/debug_toolbar/utils/tracking/db.py index 4d87090..01b4331 100644 --- a/debug_toolbar/utils/tracking/db.py +++ b/debug_toolbar/utils/tracking/db.py @@ -146,10 +146,17 @@ class NormalCursorWrapper(object): } if engine == 'psycopg2': + # If an erroneous query was ran on the connection, it might + # be in a state where checking isolation_level raises an + # exception. + try: + iso_level = conn.isolation_level + except conn.InternalError: + iso_level = 'unknown' params.update({ 'trans_id': self.logger.get_transaction_id(alias), 'trans_status': conn.get_transaction_status(), - 'iso_level': conn.isolation_level, + 'iso_level': iso_level, 'encoding': conn.encoding, }) -- cgit v1.2.3 From c1f7b3a273600b94dc433902c0a480dc8874d26a Mon Sep 17 00:00:00 2001 From: Anssi Kääriäinen Date: Mon, 27 Aug 2012 15:29:20 +0300 Subject: Made usable connections with alias not in db.connections --- debug_toolbar/utils/tracking/db.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/debug_toolbar/utils/tracking/db.py b/debug_toolbar/utils/tracking/db.py index 01b4331..2c82920 100644 --- a/debug_toolbar/utils/tracking/db.py +++ b/debug_toolbar/utils/tracking/db.py @@ -88,6 +88,14 @@ class NormalCursorWrapper(object): try: return self.cursor.execute(sql, params) finally: + # FIXME: Sometimes connections which are not in the connections + # dict are used (for example in test database destroying). + # The code below (at least get_transaction_id(alias) needs to have + # the connection in the connections dict. It would be good to + # not have this requirement at all, but for now lets just skip + # these connections. + if self.db.alias not in connections: + return stop = datetime.now() duration = ms_from_timedelta(stop - start) enable_stacktraces = getattr(settings, @@ -119,7 +127,7 @@ class NormalCursorWrapper(object): del cur_frame alias = getattr(self.db, 'alias', 'default') - conn = connections[alias].connection + conn = self.db.connection # HACK: avoid imports if conn: engine = conn.__class__.__module__.split('.', 1)[0] -- cgit v1.2.3 From 18bd5da161716eea743fcce1e9f82f0e79f1505c Mon Sep 17 00:00:00 2001 From: Anssi Kääriäinen Date: Mon, 27 Aug 2012 15:05:05 +0300 Subject: Made possible to use DJANGO_SETTINGS_MODULE in testing Also added a dummy test_pgsql settings file. --- runtests.py | 5 ++++- test_pgsql.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 test_pgsql.py diff --git a/runtests.py b/runtests.py index 3432f8b..ed49824 100644 --- a/runtests.py +++ b/runtests.py @@ -1,11 +1,14 @@ #!/usr/bin/env python import sys +import os from os.path import dirname, abspath from optparse import OptionParser from django.conf import settings, global_settings -if not settings.configured: +# For convenience configure settings if they are not pre-configured or if we +# haven't been provided settings to use by environment variable. +if not settings.configured and not os.environ.get('DJANGO_SETTINGS_MODULE'): settings.configure( DATABASES={ 'default': { diff --git a/test_pgsql.py b/test_pgsql.py new file mode 100644 index 0000000..28c0178 --- /dev/null +++ b/test_pgsql.py @@ -0,0 +1,28 @@ +from django.conf import global_settings +DATABASES={ + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + # Edit the below settings before use... + 'USER': '', + 'NAME': '', + 'HOST': '', + 'PASSWORD': '', + } +} +INSTALLED_APPS=[ + 'django.contrib.auth', + 'django.contrib.admin', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + + 'debug_toolbar', + + 'tests', +] +MIDDLEWARE_CLASSES=global_settings.MIDDLEWARE_CLASSES + ( + 'debug_toolbar.middleware.DebugToolbarMiddleware', +) +ROOT_URLCONF='' +DEBUG=False +SITE_ID=1 -- cgit v1.2.3 From 54f4f3a7361ae711641b511df5a4c8962ad623a4 Mon Sep 17 00:00:00 2001 From: Anssi Kääriäinen Date: Mon, 27 Aug 2012 14:22:25 +0300 Subject: Tests for issue_230 --- tests/tests.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/tests.py b/tests/tests.py index ea2938d..a3618bf 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -2,9 +2,11 @@ import thread from django.conf import settings from django.contrib.auth.models import User +from django.db import connection from django.http import HttpResponse from django.test import TestCase, RequestFactory from django.template import Template, Context +from django.utils import unittest from debug_toolbar.middleware import DebugToolbarMiddleware from debug_toolbar.panels.sql import SQLDebugPanel @@ -214,6 +216,19 @@ class SQLPanelTestCase(BaseTestCase): # ensure the stacktrace is populated self.assertTrue(len(query[1]['stacktrace']) > 0) + @unittest.skipUnless(connection.vendor=='postgresql', + 'Test valid only on PostgreSQL') + def test_erroneous_query(self): + """ + Test that an error in the query isn't swallowed by the middleware. + """ + from django.db import connection + from django.db.utils import DatabaseError + try: + connection.cursor().execute("erroneous query") + except DatabaseError as e: + self.assertTrue('erroneous query' in str(e)) + def test_disable_stacktraces(self): panel = self.toolbar.get_panel(SQLDebugPanel) self.assertEquals(len(panel._queries), 0) -- cgit v1.2.3