From 7365ee3ec93ce94dfedd2ae1337a14a8af4428db Mon Sep 17 00:00:00 2001 From: Brenton Partridge Date: Wed, 9 Feb 2022 18:07:48 -0800 Subject: [PATCH] Prevent TypeError when bytes passed to cursor.execute in debug middleware If DjangoDebugMiddleware is installed, calling `cursor.execute(b)` where b is a `bytes` object causes the recording (and thus the entire database call) to throw a TypeError due to https://github.com/graphql-python/graphene-django/blob/775644b5369bdc5fbb45d3535ae391a069ebf9d4/graphene_django/debug/sql/tracking.py#L126 : ``` "is_select": sql.lower().strip().startswith("select"), ``` Calling execute with a bytes parameter, to my knowledge, is not currently done within the high-level abstractions in the Django ORM, but is very much supported by psycopg2, as evidenced by the use in psycopg2's own `execute_values` in https://github.com/psycopg/psycopg2/blob/2_9_3/lib/extras.py#L1270 : ``` cur.execute(b''.join(parts)) ``` This fix ensures that the sql parameter is safely decoded before scanning whether it begins with SELECT; since this is the only usage, the change is trivial. The only workaround if code calls execute_values is to disable the DjangoDebugMiddleware altogether, which is far from ideal. --- graphene_django/debug/sql/tracking.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graphene_django/debug/sql/tracking.py b/graphene_django/debug/sql/tracking.py index bf0ea36..74bda3f 100644 --- a/graphene_django/debug/sql/tracking.py +++ b/graphene_django/debug/sql/tracking.py @@ -109,6 +109,7 @@ class NormalCursorWrapper: alias = getattr(self.db, "alias", "default") conn = self.db.connection vendor = getattr(conn, "vendor", "unknown") + sql_str = sql.decode(errors="ignore") if isinstance(sql, bytes) else sql params = { "vendor": vendor, @@ -122,7 +123,7 @@ class NormalCursorWrapper: "start_time": start_time, "stop_time": stop_time, "is_slow": duration > 10, - "is_select": sql.lower().strip().startswith("select"), + "is_select": sql_str.lower().strip().startswith("select"), } if vendor == "postgresql":