Skip to content

Commit 98ebfbe

Browse files
committed
Handle SQL commands executed using as psycopg2 Composed object
The Composed object is the recommended way of composing SQL statements. The SQL panel is currently expecting an string sql. Executing a composed sql command will cause the following exception: ``` ====================================================================== ERROR: test_execute_with_psycopg2_composed_sql (tests.panels.test_sql.SQLPanelTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/haki/src/django-debug-toolbar/tests/panels/test_sql.py", line 228, in test_execute_with_psycopg2_composed_sql cursor.execute(command) File "/home/haki/src/django-debug-toolbar/debug_toolbar/panels/sql/tracking.py", line 184, in execute return self._record(self.cursor.execute, sql, params) File "/home/haki/src/django-debug-toolbar/debug_toolbar/panels/sql/tracking.py", line 156, in _record "is_select": sql.lower().strip().startswith("select"), AttributeError: 'Composed' object has no attribute 'lower' ``` The solution is to cast the sql to string. If it's already string - no harm. If it's a `Composable` object, it will return the composed SQL as str.
1 parent 475d9d5 commit 98ebfbe

File tree

2 files changed

+29
-0
lines changed

2 files changed

+29
-0
lines changed

debug_toolbar/panels/sql/tracking.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ def _record(self, method, sql, params):
135135
conn = self.db.connection
136136
vendor = getattr(conn, "vendor", "unknown")
137137

138+
# Sql might be an object (such as psycopg Composed).
139+
# For logging purposes, make sure it's str.
140+
sql = str(sql)
141+
138142
params = {
139143
"vendor": vendor,
140144
"alias": alias,

tests/panels/test_sql.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,31 @@ def test_erroneous_query(self):
209209
except DatabaseError as e:
210210
self.assertTrue("erroneous query" in str(e))
211211

212+
@unittest.skipUnless(
213+
connection.vendor == "postgresql", "Test valid only on PostgreSQL"
214+
)
215+
def test_execute_with_psycopg2_composed_sql(self):
216+
"""
217+
Test command executed using a Composed psycopg2 object is logged.
218+
Ref: http://initd.org/psycopg/docs/sql.html
219+
"""
220+
from psycopg2 import sql
221+
222+
self.assertEqual(len(self.panel._queries), 0)
223+
224+
with connection.cursor() as cursor:
225+
command = sql.SQL("select {field} from {table}").format(
226+
field=sql.Identifier("username"), table=sql.Identifier("auth_user")
227+
)
228+
cursor.execute(command)
229+
230+
self.assertEqual(len(self.panel._queries), 1)
231+
232+
query = self.panel._queries[0]
233+
self.assertEqual(query[0], "default")
234+
self.assertTrue("sql" in query[1])
235+
self.assertEqual(query[1]["sql"], 'select "username" from "auth_user"')
236+
212237
def test_disable_stacktraces(self):
213238
self.assertEqual(len(self.panel._queries), 0)
214239

0 commit comments

Comments
 (0)