Browse Source

Fixed #33717 -- Dropped support for PostgreSQL 11.

Mariusz Felisiak 2 years ago
parent
commit
981c23c0cc

+ 0 - 9
django/contrib/postgres/constraints.py

@@ -142,15 +142,6 @@ class ExclusionConstraint(BaseConstraint):
         )
 
     def check_supported(self, schema_editor):
-        if (
-            self.include
-            and self.index_type.lower() == "gist"
-            and not schema_editor.connection.features.supports_covering_gist_indexes
-        ):
-            raise NotSupportedError(
-                "Covering exclusion constraints using a GiST index require "
-                "PostgreSQL 12+."
-            )
         if (
             self.include
             and self.index_type.lower() == "spgist"

+ 0 - 7
django/contrib/postgres/indexes.py

@@ -187,13 +187,6 @@ class GistIndex(PostgresIndex):
             with_params.append("fillfactor = %d" % self.fillfactor)
         return with_params
 
-    def check_supported(self, schema_editor):
-        if (
-            self.include
-            and not schema_editor.connection.features.supports_covering_gist_indexes
-        ):
-            raise NotSupportedError("Covering GiST indexes require PostgreSQL 12+.")
-
 
 class HashIndex(PostgresIndex):
     suffix = "hash"

+ 0 - 6
django/contrib/postgres/operations.py

@@ -185,12 +185,6 @@ class CollationOperation(Operation):
         )
 
     def create_collation(self, schema_editor):
-        if self.deterministic is False and not (
-            schema_editor.connection.features.supports_non_deterministic_collations
-        ):
-            raise NotSupportedError(
-                "Non-deterministic collations require PostgreSQL 12+."
-            )
         args = {"locale": schema_editor.quote_name(self.locale)}
         if self.provider != "libc":
             args["provider"] = schema_editor.quote_name(self.provider)

+ 1 - 9
django/db/backends/postgresql/features.py

@@ -6,7 +6,7 @@ from django.utils.functional import cached_property
 
 
 class DatabaseFeatures(BaseDatabaseFeatures):
-    minimum_database_version = (11,)
+    minimum_database_version = (12,)
     allows_group_by_selected_pks = True
     can_return_columns_from_insert = True
     can_return_rows_from_bulk_insert = True
@@ -83,10 +83,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
             "PositiveSmallIntegerField": "SmallIntegerField",
         }
 
-    @cached_property
-    def is_postgresql_12(self):
-        return self.connection.pg_version >= 120000
-
     @cached_property
     def is_postgresql_13(self):
         return self.connection.pg_version >= 130000
@@ -96,8 +92,4 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         return self.connection.pg_version >= 140000
 
     has_bit_xor = property(operator.attrgetter("is_postgresql_14"))
-    supports_covering_gist_indexes = property(operator.attrgetter("is_postgresql_12"))
     supports_covering_spgist_indexes = property(operator.attrgetter("is_postgresql_14"))
-    supports_non_deterministic_collations = property(
-        operator.attrgetter("is_postgresql_12")
-    )

+ 1 - 1
docs/ref/contrib/gis/install/index.txt

@@ -58,7 +58,7 @@ supported versions, and any notes for each of the supported database backends:
 ==================  ==============================  ==================  =========================================
 Database            Library Requirements            Supported Versions  Notes
 ==================  ==============================  ==================  =========================================
-PostgreSQL          GEOS, GDAL, PROJ, PostGIS       11+                 Requires PostGIS.
+PostgreSQL          GEOS, GDAL, PROJ, PostGIS       12+                 Requires PostGIS.
 MySQL               GEOS, GDAL                      5.7+                :ref:`Limited functionality <mysql-spatial-limitations>`.
 Oracle              GEOS, GDAL                      19+                 XE not supported.
 SQLite              GEOS, GDAL, PROJ, SpatiaLite    3.9.0+              Requires SpatiaLite 4.3+

+ 2 - 2
docs/ref/contrib/postgres/constraints.txt

@@ -139,8 +139,8 @@ used for queries that select only included fields
 (:attr:`~ExclusionConstraint.include`) and filter only by indexed fields
 (:attr:`~ExclusionConstraint.expressions`).
 
-``include`` is supported for GiST indexes on PostgreSQL 12+ and SP-GiST
-indexes on PostgreSQL 14+.
+``include`` is supported for GiST indexes. PostgreSQL 14+ also supports
+``include`` for SP-GiST indexes.
 
 .. versionchanged:: 4.1
 

+ 2 - 2
docs/ref/contrib/postgres/fields.txt

@@ -287,8 +287,8 @@ transform do not change. For example::
 
 .. admonition:: Case-insensitive collations
 
-    On PostgreSQL 12+, it's preferable to use non-deterministic collations
-    instead of the ``citext`` extension. You can create them using the
+    It's preferable to use non-deterministic collations instead of the
+    ``citext`` extension. You can create them using the
     :class:`~django.contrib.postgres.operations.CreateCollation` migration
     operation. For more details, see :ref:`manage-postgresql-collations` and
     the PostgreSQL documentation about `non-deterministic collations`_.

+ 0 - 4
docs/ref/contrib/postgres/operations.txt

@@ -151,10 +151,6 @@ For example, to create a collation for German phone book ordering::
     ``provider``, and ``deterministic`` arguments. Therefore, ``locale`` is
     required to make this operation reversible.
 
-.. admonition:: Restrictions
-
-    Non-deterministic collations are supported only on PostgreSQL 12+.
-
 Concurrent index operations
 ===========================
 

+ 1 - 1
docs/ref/databases.txt

@@ -114,7 +114,7 @@ below for information on how to set up your database correctly.
 PostgreSQL notes
 ================
 
-Django supports PostgreSQL 11 and higher. `psycopg2`_ 2.8.4 or higher is
+Django supports PostgreSQL 12 and higher. `psycopg2`_ 2.8.4 or higher is
 required, though the latest release is recommended.
 
 .. _psycopg2: https://www.psycopg.org/

+ 3 - 4
docs/ref/models/indexes.txt

@@ -214,10 +214,9 @@ See the PostgreSQL documentation for more details about `covering indexes`_.
 
 .. admonition:: Restrictions on PostgreSQL
 
-    PostgreSQL < 12 only supports covering B-Tree indexes, PostgreSQL 12+ also
-    supports covering :class:`GiST indexes
-    <django.contrib.postgres.indexes.GistIndex>`, and PostgreSQL 14+ also
-    supports covering :class:`SP-GiST indexes
+    PostgreSQL supports covering B-Tree and :class:`GiST indexes
+    <django.contrib.postgres.indexes.GistIndex>`. PostgreSQL 14+ also supports
+    covering :class:`SP-GiST indexes
     <django.contrib.postgres.indexes.SpGistIndex>`.
 
 .. versionchanged:: 4.1

+ 6 - 0
docs/releases/4.2.txt

@@ -229,6 +229,12 @@ Dropped support for MariaDB 10.3
 Upstream support for MariaDB 10.3 ends in May 2023. Django 4.2 supports MariaDB
 10.4 and higher.
 
+Dropped support for PostgreSQL 11
+---------------------------------
+
+Upstream support for PostgreSQL 11 ends in November 2023. Django 4.2 supports
+PostgreSQL 12 and higher.
+
 Miscellaneous
 -------------
 

+ 2 - 2
tests/backends/postgresql/tests.py

@@ -315,9 +315,9 @@ class Tests(TestCase):
         new_connection.pg_version = 110009
         self.assertEqual(new_connection.get_database_version(), (11, 9))
 
-    @mock.patch.object(connection, "get_database_version", return_value=(10,))
+    @mock.patch.object(connection, "get_database_version", return_value=(11,))
     def test_check_database_version_supported(self, mocked_get_database_version):
-        msg = "PostgreSQL 11 or later is required (found 10)."
+        msg = "PostgreSQL 12 or later is required (found 11)."
         with self.assertRaisesMessage(NotSupportedError, msg):
             connection.check_database_version_supported()
         self.assertTrue(mocked_get_database_version.called)

+ 0 - 26
tests/postgres_tests/test_constraints.py

@@ -845,7 +845,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
         RangesModel.objects.create(ints=(10, 19))
         RangesModel.objects.create(ints=(51, 60))
 
-    @skipUnlessDBFeature("supports_covering_gist_indexes")
     def test_range_adjacent_gist_include(self):
         constraint_name = "ints_adjacent_gist_include"
         self.assertNotIn(
@@ -887,7 +886,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
         RangesModel.objects.create(ints=(10, 19))
         RangesModel.objects.create(ints=(51, 60))
 
-    @skipUnlessDBFeature("supports_covering_gist_indexes")
     def test_range_adjacent_gist_include_condition(self):
         constraint_name = "ints_adjacent_gist_include_condition"
         self.assertNotIn(
@@ -921,7 +919,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
             editor.add_constraint(RangesModel, constraint)
         self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
 
-    @skipUnlessDBFeature("supports_covering_gist_indexes")
     def test_range_adjacent_gist_include_deferrable(self):
         constraint_name = "ints_adjacent_gist_include_deferrable"
         self.assertNotIn(
@@ -955,27 +952,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
             editor.add_constraint(RangesModel, constraint)
         self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
 
-    def test_gist_include_not_supported(self):
-        constraint_name = "ints_adjacent_gist_include_not_supported"
-        constraint = ExclusionConstraint(
-            name=constraint_name,
-            expressions=[("ints", RangeOperators.ADJACENT_TO)],
-            index_type="gist",
-            include=["id"],
-        )
-        msg = (
-            "Covering exclusion constraints using a GiST index require "
-            "PostgreSQL 12+."
-        )
-        with connection.schema_editor() as editor:
-            with mock.patch(
-                "django.db.backends.postgresql.features.DatabaseFeatures."
-                "supports_covering_gist_indexes",
-                False,
-            ):
-                with self.assertRaisesMessage(NotSupportedError, msg):
-                    editor.add_constraint(RangesModel, constraint)
-
     def test_spgist_include_not_supported(self):
         constraint_name = "ints_adjacent_spgist_include_not_supported"
         constraint = ExclusionConstraint(
@@ -1062,7 +1038,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
             editor.add_constraint(RangesModel, constraint)
         self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
 
-    @skipUnlessDBFeature("supports_covering_gist_indexes")
     def test_range_adjacent_gist_opclass_include(self):
         constraint_name = "ints_adjacent_gist_opclass_include"
         self.assertNotIn(
@@ -1210,7 +1185,6 @@ class ExclusionConstraintOpclassesDepracationTests(PostgreSQLTestCase):
         self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
 
     @ignore_warnings(category=RemovedInDjango50Warning)
-    @skipUnlessDBFeature("supports_covering_gist_indexes")
     def test_range_adjacent_gist_opclasses_include(self):
         constraint_name = "ints_adjacent_gist_opclasses_include"
         self.assertNotIn(

+ 0 - 15
tests/postgres_tests/test_indexes.py

@@ -505,7 +505,6 @@ class SchemaTests(PostgreSQLTestCase):
             index_name, self.get_constraints(CharFieldModel._meta.db_table)
         )
 
-    @skipUnlessDBFeature("supports_covering_gist_indexes")
     def test_gist_include(self):
         index_name = "scene_gist_include_setting"
         index = GistIndex(name=index_name, fields=["scene"], include=["setting"])
@@ -519,20 +518,6 @@ class SchemaTests(PostgreSQLTestCase):
             editor.remove_index(Scene, index)
         self.assertNotIn(index_name, self.get_constraints(Scene._meta.db_table))
 
-    def test_gist_include_not_supported(self):
-        index_name = "gist_include_exception"
-        index = GistIndex(fields=["scene"], name=index_name, include=["setting"])
-        msg = "Covering GiST indexes require PostgreSQL 12+."
-        with self.assertRaisesMessage(NotSupportedError, msg):
-            with mock.patch(
-                "django.db.backends.postgresql.features.DatabaseFeatures."
-                "supports_covering_gist_indexes",
-                False,
-            ):
-                with connection.schema_editor() as editor:
-                    editor.add_index(Scene, index)
-        self.assertNotIn(index_name, self.get_constraints(Scene._meta.db_table))
-
     def test_tsvector_op_class_gist_index(self):
         index_name = "tsvector_op_class_gist"
         index = GistIndex(

+ 1 - 24
tests/postgres_tests/test_operations.py

@@ -1,5 +1,4 @@
 import unittest
-from unittest import mock
 
 from migrations.test_base import OperationTestBase
 
@@ -7,7 +6,7 @@ from django.db import IntegrityError, NotSupportedError, connection, transaction
 from django.db.migrations.state import ProjectState
 from django.db.models import CheckConstraint, Index, Q, UniqueConstraint
 from django.db.utils import ProgrammingError
-from django.test import modify_settings, override_settings, skipUnlessDBFeature
+from django.test import modify_settings, override_settings
 from django.test.utils import CaptureQueriesContext
 
 from . import PostgreSQLTestCase
@@ -318,7 +317,6 @@ class CreateCollationTests(PostgreSQLTestCase):
         self.assertEqual(args, [])
         self.assertEqual(kwargs, {"name": "C_test", "locale": "C"})
 
-    @skipUnlessDBFeature("supports_non_deterministic_collations")
     def test_create_non_deterministic_collation(self):
         operation = CreateCollation(
             "case_insensitive_test",
@@ -383,27 +381,6 @@ class CreateCollationTests(PostgreSQLTestCase):
         self.assertEqual(len(captured_queries), 1)
         self.assertIn("DROP COLLATION", captured_queries[0]["sql"])
 
-    def test_nondeterministic_collation_not_supported(self):
-        operation = CreateCollation(
-            "case_insensitive_test",
-            provider="icu",
-            locale="und-u-ks-level2",
-            deterministic=False,
-        )
-        project_state = ProjectState()
-        new_state = project_state.clone()
-        msg = "Non-deterministic collations require PostgreSQL 12+."
-        with connection.schema_editor(atomic=False) as editor:
-            with mock.patch(
-                "django.db.backends.postgresql.features.DatabaseFeatures."
-                "supports_non_deterministic_collations",
-                False,
-            ):
-                with self.assertRaisesMessage(NotSupportedError, msg):
-                    operation.database_forwards(
-                        self.app_label, editor, project_state, new_state
-                    )
-
 
 @unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific tests.")
 class RemoveCollationTests(PostgreSQLTestCase):

+ 2 - 4
tests/postgres_tests/test_trigram.py

@@ -46,8 +46,7 @@ class TrigramTest(PostgreSQLTestCase):
 
     def test_trigram_similarity(self):
         search = "Bat sat on cat."
-        # Round result of similarity because PostgreSQL 12+ uses greater
-        # precision.
+        # Round result of similarity because PostgreSQL uses greater precision.
         self.assertQuerysetEqual(
             self.Model.objects.filter(
                 field__trigram_similar=search,
@@ -77,8 +76,7 @@ class TrigramTest(PostgreSQLTestCase):
         )
 
     def test_trigram_similarity_alternate(self):
-        # Round result of distance because PostgreSQL 12+ uses greater
-        # precision.
+        # Round result of distance because PostgreSQL uses greater precision.
         self.assertQuerysetEqual(
             self.Model.objects.annotate(
                 distance=TrigramDistance("field", "Bat sat on cat."),

+ 1 - 2
tests/queries/test_explain.py

@@ -82,9 +82,8 @@ class ExplainTests(TestCase):
             {"verbose": True, "timing": True, "analyze": True},
             {"verbose": False, "timing": False, "analyze": True},
             {"summary": True},
+            {"settings": True},
         ]
-        if connection.features.is_postgresql_12:
-            test_options.append({"settings": True})
         if connection.features.is_postgresql_13:
             test_options.append({"analyze": True, "wal": True})
         for options in test_options: