Browse Source

Fixed #35294 -- Fixed TEXT format of QuerySet.explain() for long plans.

co-authored-by: Gordon <gordon.wrigley@gmail.com>
co-authored-by: Simon Charette <charette.s@gmail.com>
Adam Johnson 1 year ago
parent
commit
cbf1e87398
2 changed files with 15 additions and 5 deletions
  1. 6 5
      django/db/models/sql/compiler.py
  2. 9 0
      tests/queries/test_explain.py

+ 6 - 5
django/db/models/sql/compiler.py

@@ -1621,11 +1621,12 @@ class SQLCompiler:
         # tuples with integers and strings. Flatten them out into strings.
         format_ = self.query.explain_info.format
         output_formatter = json.dumps if format_ and format_.lower() == "json" else str
-        for row in result[0]:
-            if not isinstance(row, str):
-                yield " ".join(output_formatter(c) for c in row)
-            else:
-                yield row
+        for row in result:
+            for value in row:
+                if not isinstance(value, str):
+                    yield " ".join([output_formatter(c) for c in value])
+                else:
+                    yield value
 
 
 class SQLInsertCompiler(SQLCompiler):

+ 9 - 0
tests/queries/test_explain.py

@@ -96,6 +96,15 @@ class ExplainTests(TestCase):
                     option = "{} {}".format(name.upper(), "true" if value else "false")
                     self.assertIn(option, captured_queries[0]["sql"])
 
+    def test_multi_page_text_explain(self):
+        if "TEXT" not in connection.features.supported_explain_formats:
+            self.skipTest("This backend does not support TEXT format.")
+
+        base_qs = Tag.objects.order_by()
+        qs = base_qs.filter(name="test").union(*[base_qs for _ in range(100)])
+        result = qs.explain(format="text")
+        self.assertGreaterEqual(result.count("\n"), 100)
+
     def test_option_sql_injection(self):
         qs = Tag.objects.filter(name="test")
         options = {"SUMMARY true) SELECT 1; --": True}