Browse Source

Fixed #35856 -- Added QuerySet.explain() support for MEMORY/SERIALIZE option on PostgreSQL 17+.

Anthony Joseph 5 tháng trước cách đây
mục cha
commit
3a8f52fbc6

+ 4 - 0
django/db/backends/postgresql/features.py

@@ -160,6 +160,10 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     def is_postgresql_16(self):
         return self.connection.pg_version >= 160000
 
+    @cached_property
+    def is_postgresql_17(self):
+        return self.connection.pg_version >= 170000
+
     supports_unlimited_charfield = True
     supports_nulls_distinct_unique_constraints = property(
         operator.attrgetter("is_postgresql_15")

+ 5 - 0
django/db/backends/postgresql/operations.py

@@ -32,7 +32,9 @@ class DatabaseOperations(BaseDatabaseOperations):
             "BUFFERS",
             "COSTS",
             "GENERIC_PLAN",
+            "MEMORY",
             "SETTINGS",
+            "SERIALIZE",
             "SUMMARY",
             "TIMING",
             "VERBOSE",
@@ -365,6 +367,9 @@ class DatabaseOperations(BaseDatabaseOperations):
 
     def explain_query_prefix(self, format=None, **options):
         extra = {}
+        if serialize := options.pop("serialize", None):
+            if serialize.upper() in {"TEXT", "BINARY"}:
+                extra["SERIALIZE"] = serialize.upper()
         # Normalize options.
         if options:
             options = {

+ 5 - 0
docs/ref/models/querysets.txt

@@ -3110,6 +3110,11 @@ there are triggers or if a function is called, even for a ``SELECT`` query.
 
     Support for the ``generic_plan`` option on PostgreSQL 16+ was added.
 
+.. versionchanged:: 5.2
+
+    Support for the ``memory`` and ``serialize`` options on PostgreSQL 17+ was
+    added.
+
 .. _field-lookups:
 
 ``Field`` lookups

+ 3 - 0
docs/releases/5.2.txt

@@ -277,6 +277,9 @@ Models
   longer required to be set on SQLite, which supports unlimited ``VARCHAR``
   columns.
 
+* :meth:`.QuerySet.explain` now supports the ``memory`` and ``serialize``
+  options on PostgreSQL 17+.
+
 Requests and Responses
 ~~~~~~~~~~~~~~~~~~~~~~
 

+ 12 - 1
tests/queries/test_explain.py

@@ -90,13 +90,24 @@ class ExplainTests(TestCase):
         ]
         if connection.features.is_postgresql_16:
             test_options.append({"generic_plan": True})
+        if connection.features.is_postgresql_17:
+            test_options.append({"memory": True})
+            test_options.append({"serialize": "TEXT", "analyze": True})
+            test_options.append({"serialize": "text", "analyze": True})
+            test_options.append({"serialize": "BINARY", "analyze": True})
+            test_options.append({"serialize": "binary", "analyze": True})
         for options in test_options:
             with self.subTest(**options), transaction.atomic():
                 with CaptureQueriesContext(connection) as captured_queries:
                     qs.explain(format="text", **options)
                 self.assertEqual(len(captured_queries), 1)
                 for name, value in options.items():
-                    option = "{} {}".format(name.upper(), "true" if value else "false")
+                    if isinstance(value, str):
+                        option = "{} {}".format(name.upper(), value.upper())
+                    else:
+                        option = "{} {}".format(
+                            name.upper(), "true" if value else "false"
+                        )
                     self.assertIn(option, captured_queries[0]["sql"])
 
     @skipUnlessDBFeature("supports_select_union")