Browse Source

Refs #32943 -- Added support for covering SP-GiST indexes on PostgreSQL 14+.

Nick Pope 3 years ago
parent
commit
e76f9d5b44

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

@@ -220,6 +220,13 @@ class SpGistIndex(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_spgist_indexes
+        ):
+            raise NotSupportedError('Covering SP-GiST indexes require PostgreSQL 14+.')
+
 
 class OpClass(Func):
     template = '%(expressions)s %(name)s'

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

@@ -99,4 +99,5 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     has_websearch_to_tsquery = property(operator.attrgetter('is_postgresql_11'))
     supports_covering_indexes = property(operator.attrgetter('is_postgresql_11'))
     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'))

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

@@ -138,6 +138,10 @@ available from the ``django.contrib.postgres.indexes`` module.
     Provide an integer value from 10 to 100 to the fillfactor_ parameter to
     tune how packed the index pages will be. PostgreSQL's default is 90.
 
+    .. versionchanged:: 4.1
+
+        Support for covering SP-GiST indexes on PostgreSQL 14+ was added.
+
     .. _fillfactor: https://www.postgresql.org/docs/current/sql-createindex.html#SQL-CREATEINDEX-STORAGE-PARAMETERS
 
 ``OpClass()`` expressions

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

@@ -210,8 +210,14 @@ See the PostgreSQL documentation for more details about `covering indexes`_.
 
 .. admonition:: Restrictions on PostgreSQL
 
-    PostgreSQL 11+ only supports covering B-Tree indexes, and PostgreSQL 12+
-    also supports covering :class:`GiST indexes
-    <django.contrib.postgres.indexes.GistIndex>`.
+    PostgreSQL 11+ 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
+    <django.contrib.postgres.indexes.SpGistIndex>`.
+
+.. versionchanged:: 4.1
+
+    Support for covering SP-GiST indexes with PostgreSQL 14+ was added.
 
 .. _covering indexes: https://www.postgresql.org/docs/current/indexes-index-only-scans.html

+ 3 - 0
docs/releases/4.1.txt

@@ -68,6 +68,9 @@ Minor features
   aggregate function returns an ``int`` of the bitwise ``XOR`` of all non-null
   input values.
 
+* :class:`~django.contrib.postgres.indexes.SpGistIndex` now supports covering
+  indexes on PostgreSQL 14+.
+
 :mod:`django.contrib.redirects`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

+ 1 - 0
docs/spelling_wordlist

@@ -196,6 +196,7 @@ geospatial
 Gettext
 GiB
 gis
+GiST
 Googol
 Greenhill
 gunicorn

+ 1 - 1
tests/postgres_tests/migrations/0002_create_test_models.py

@@ -142,7 +142,7 @@ class Migration(migrations.Migration):
             name='Scene',
             fields=[
                 ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
-                ('scene', models.CharField(max_length=255)),
+                ('scene', models.TextField()),
                 ('setting', models.CharField(max_length=255)),
             ],
             options=None,

+ 1 - 1
tests/postgres_tests/models.py

@@ -101,7 +101,7 @@ class BigAutoFieldModel(models.Model):
 # Scene/Character/Line models are used to test full text search. They're
 # populated with content from Monty Python and the Holy Grail.
 class Scene(models.Model):
-    scene = models.CharField(max_length=255)
+    scene = models.TextField()
     setting = models.CharField(max_length=255)
 
 

+ 27 - 0
tests/postgres_tests/test_indexes.py

@@ -518,6 +518,33 @@ class SchemaTests(PostgreSQLTestCase):
             editor.remove_index(TextFieldModel, index)
         self.assertNotIn(index_name, self.get_constraints(TextFieldModel._meta.db_table))
 
+    @skipUnlessDBFeature('supports_covering_spgist_indexes')
+    def test_spgist_include(self):
+        index_name = 'scene_spgist_include_setting'
+        index = SpGistIndex(name=index_name, fields=['scene'], include=['setting'])
+        with connection.schema_editor() as editor:
+            editor.add_index(Scene, index)
+        constraints = self.get_constraints(Scene._meta.db_table)
+        self.assertIn(index_name, constraints)
+        self.assertEqual(constraints[index_name]['type'], SpGistIndex.suffix)
+        self.assertEqual(constraints[index_name]['columns'], ['scene', 'setting'])
+        with connection.schema_editor() as editor:
+            editor.remove_index(Scene, index)
+        self.assertNotIn(index_name, self.get_constraints(Scene._meta.db_table))
+
+    def test_spgist_include_not_supported(self):
+        index_name = 'spgist_include_exception'
+        index = SpGistIndex(fields=['scene'], name=index_name, include=['setting'])
+        msg = 'Covering SP-GiST indexes require PostgreSQL 14+.'
+        with self.assertRaisesMessage(NotSupportedError, msg):
+            with mock.patch(
+                'django.db.backends.postgresql.features.DatabaseFeatures.supports_covering_spgist_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_op_class(self):
         index_name = 'test_op_class'
         index = Index(