Fixed #33717 -- Dropped support for PostgreSQL 11.

This commit is contained in:
Mariusz Felisiak 2022-05-19 09:26:48 +02:00 committed by GitHub
parent 9f55489529
commit 981c23c0cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 22 additions and 118 deletions

View File

@ -142,15 +142,6 @@ class ExclusionConstraint(BaseConstraint):
) )
def check_supported(self, schema_editor): 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 ( if (
self.include self.include
and self.index_type.lower() == "spgist" and self.index_type.lower() == "spgist"

View File

@ -187,13 +187,6 @@ class GistIndex(PostgresIndex):
with_params.append("fillfactor = %d" % self.fillfactor) with_params.append("fillfactor = %d" % self.fillfactor)
return with_params 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): class HashIndex(PostgresIndex):
suffix = "hash" suffix = "hash"

View File

@ -185,12 +185,6 @@ class CollationOperation(Operation):
) )
def create_collation(self, schema_editor): 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)} args = {"locale": schema_editor.quote_name(self.locale)}
if self.provider != "libc": if self.provider != "libc":
args["provider"] = schema_editor.quote_name(self.provider) args["provider"] = schema_editor.quote_name(self.provider)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -114,7 +114,7 @@ below for information on how to set up your database correctly.
PostgreSQL notes 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. required, though the latest release is recommended.
.. _psycopg2: https://www.psycopg.org/ .. _psycopg2: https://www.psycopg.org/

View File

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

View File

@ -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 Upstream support for MariaDB 10.3 ends in May 2023. Django 4.2 supports MariaDB
10.4 and higher. 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 Miscellaneous
------------- -------------

View File

@ -315,9 +315,9 @@ class Tests(TestCase):
new_connection.pg_version = 110009 new_connection.pg_version = 110009
self.assertEqual(new_connection.get_database_version(), (11, 9)) 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): 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): with self.assertRaisesMessage(NotSupportedError, msg):
connection.check_database_version_supported() connection.check_database_version_supported()
self.assertTrue(mocked_get_database_version.called) self.assertTrue(mocked_get_database_version.called)

View File

@ -845,7 +845,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
RangesModel.objects.create(ints=(10, 19)) RangesModel.objects.create(ints=(10, 19))
RangesModel.objects.create(ints=(51, 60)) RangesModel.objects.create(ints=(51, 60))
@skipUnlessDBFeature("supports_covering_gist_indexes")
def test_range_adjacent_gist_include(self): def test_range_adjacent_gist_include(self):
constraint_name = "ints_adjacent_gist_include" constraint_name = "ints_adjacent_gist_include"
self.assertNotIn( self.assertNotIn(
@ -887,7 +886,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
RangesModel.objects.create(ints=(10, 19)) RangesModel.objects.create(ints=(10, 19))
RangesModel.objects.create(ints=(51, 60)) RangesModel.objects.create(ints=(51, 60))
@skipUnlessDBFeature("supports_covering_gist_indexes")
def test_range_adjacent_gist_include_condition(self): def test_range_adjacent_gist_include_condition(self):
constraint_name = "ints_adjacent_gist_include_condition" constraint_name = "ints_adjacent_gist_include_condition"
self.assertNotIn( self.assertNotIn(
@ -921,7 +919,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
editor.add_constraint(RangesModel, constraint) editor.add_constraint(RangesModel, constraint)
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table)) self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
@skipUnlessDBFeature("supports_covering_gist_indexes")
def test_range_adjacent_gist_include_deferrable(self): def test_range_adjacent_gist_include_deferrable(self):
constraint_name = "ints_adjacent_gist_include_deferrable" constraint_name = "ints_adjacent_gist_include_deferrable"
self.assertNotIn( self.assertNotIn(
@ -955,27 +952,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
editor.add_constraint(RangesModel, constraint) editor.add_constraint(RangesModel, constraint)
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table)) 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): def test_spgist_include_not_supported(self):
constraint_name = "ints_adjacent_spgist_include_not_supported" constraint_name = "ints_adjacent_spgist_include_not_supported"
constraint = ExclusionConstraint( constraint = ExclusionConstraint(
@ -1062,7 +1038,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
editor.add_constraint(RangesModel, constraint) editor.add_constraint(RangesModel, constraint)
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table)) self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
@skipUnlessDBFeature("supports_covering_gist_indexes")
def test_range_adjacent_gist_opclass_include(self): def test_range_adjacent_gist_opclass_include(self):
constraint_name = "ints_adjacent_gist_opclass_include" constraint_name = "ints_adjacent_gist_opclass_include"
self.assertNotIn( self.assertNotIn(
@ -1210,7 +1185,6 @@ class ExclusionConstraintOpclassesDepracationTests(PostgreSQLTestCase):
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table)) self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
@ignore_warnings(category=RemovedInDjango50Warning) @ignore_warnings(category=RemovedInDjango50Warning)
@skipUnlessDBFeature("supports_covering_gist_indexes")
def test_range_adjacent_gist_opclasses_include(self): def test_range_adjacent_gist_opclasses_include(self):
constraint_name = "ints_adjacent_gist_opclasses_include" constraint_name = "ints_adjacent_gist_opclasses_include"
self.assertNotIn( self.assertNotIn(

View File

@ -505,7 +505,6 @@ class SchemaTests(PostgreSQLTestCase):
index_name, self.get_constraints(CharFieldModel._meta.db_table) index_name, self.get_constraints(CharFieldModel._meta.db_table)
) )
@skipUnlessDBFeature("supports_covering_gist_indexes")
def test_gist_include(self): def test_gist_include(self):
index_name = "scene_gist_include_setting" index_name = "scene_gist_include_setting"
index = GistIndex(name=index_name, fields=["scene"], include=["setting"]) index = GistIndex(name=index_name, fields=["scene"], include=["setting"])
@ -519,20 +518,6 @@ class SchemaTests(PostgreSQLTestCase):
editor.remove_index(Scene, index) editor.remove_index(Scene, index)
self.assertNotIn(index_name, self.get_constraints(Scene._meta.db_table)) 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): def test_tsvector_op_class_gist_index(self):
index_name = "tsvector_op_class_gist" index_name = "tsvector_op_class_gist"
index = GistIndex( index = GistIndex(

View File

@ -1,5 +1,4 @@
import unittest import unittest
from unittest import mock
from migrations.test_base import OperationTestBase 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.migrations.state import ProjectState
from django.db.models import CheckConstraint, Index, Q, UniqueConstraint from django.db.models import CheckConstraint, Index, Q, UniqueConstraint
from django.db.utils import ProgrammingError 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 django.test.utils import CaptureQueriesContext
from . import PostgreSQLTestCase from . import PostgreSQLTestCase
@ -318,7 +317,6 @@ class CreateCollationTests(PostgreSQLTestCase):
self.assertEqual(args, []) self.assertEqual(args, [])
self.assertEqual(kwargs, {"name": "C_test", "locale": "C"}) self.assertEqual(kwargs, {"name": "C_test", "locale": "C"})
@skipUnlessDBFeature("supports_non_deterministic_collations")
def test_create_non_deterministic_collation(self): def test_create_non_deterministic_collation(self):
operation = CreateCollation( operation = CreateCollation(
"case_insensitive_test", "case_insensitive_test",
@ -383,27 +381,6 @@ class CreateCollationTests(PostgreSQLTestCase):
self.assertEqual(len(captured_queries), 1) self.assertEqual(len(captured_queries), 1)
self.assertIn("DROP COLLATION", captured_queries[0]["sql"]) 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.") @unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific tests.")
class RemoveCollationTests(PostgreSQLTestCase): class RemoveCollationTests(PostgreSQLTestCase):

View File

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

View File

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