diff --git a/django/contrib/postgres/indexes.py b/django/contrib/postgres/indexes.py index 34e09b19f2..1850b20978 100644 --- a/django/contrib/postgres/indexes.py +++ b/django/contrib/postgres/indexes.py @@ -1,4 +1,5 @@ from django.db.models import Index +from django.db.utils import NotSupportedError from django.utils.functional import cached_property __all__ = [ @@ -18,6 +19,7 @@ class PostgresIndex(Index): return Index.max_name_length - len(Index.suffix) + len(self.suffix) def create_sql(self, model, schema_editor, using=''): + self.check_supported(schema_editor) statement = super().create_sql(model, schema_editor, using=' USING %s' % self.suffix) with_params = self.get_with_params() if with_params: @@ -27,6 +29,9 @@ class PostgresIndex(Index): ) return statement + def check_supported(self, schema_editor): + pass + def get_with_params(self): return [] @@ -49,6 +54,12 @@ class BrinIndex(PostgresIndex): kwargs['pages_per_range'] = self.pages_per_range return path, args, kwargs + def check_supported(self, schema_editor): + if not schema_editor.connection.features.has_brin_index_support: + raise NotSupportedError('BRIN indexes require PostgreSQL 9.5+.') + if self.autosummarize and not schema_editor.connection.features.has_brin_autosummarize: + raise NotSupportedError('BRIN option autosummarize requires PostgreSQL 10+.') + def get_with_params(self): with_params = [] if self.autosummarize is not None: diff --git a/tests/postgres_tests/test_indexes.py b/tests/postgres_tests/test_indexes.py index 96ff829807..f4ac359a3a 100644 --- a/tests/postgres_tests/test_indexes.py +++ b/tests/postgres_tests/test_indexes.py @@ -1,7 +1,10 @@ +from unittest import mock + from django.contrib.postgres.indexes import ( BrinIndex, BTreeIndex, GinIndex, GistIndex, HashIndex, SpGistIndex, ) from django.db import connection +from django.db.utils import NotSupportedError from django.test import skipUnlessDBFeature from . import PostgreSQLTestCase @@ -208,6 +211,25 @@ class SchemaTests(PostgreSQLTestCase): editor.remove_index(CharFieldModel, index) self.assertNotIn(index_name, self.get_constraints(CharFieldModel._meta.db_table)) + def test_brin_index_not_supported(self): + index_name = 'brin_index_exception' + index = BrinIndex(fields=['field'], name=index_name) + with self.assertRaisesMessage(NotSupportedError, 'BRIN indexes require PostgreSQL 9.5+.'): + with mock.patch('django.db.connection.features.has_brin_index_support', False): + with connection.schema_editor() as editor: + editor.add_index(CharFieldModel, index) + self.assertNotIn(index_name, self.get_constraints(CharFieldModel._meta.db_table)) + + @skipUnlessDBFeature('has_brin_index_support') + def test_brin_autosummarize_not_supported(self): + index_name = 'brin_options_exception' + index = BrinIndex(fields=['field'], name=index_name, autosummarize=True) + with self.assertRaisesMessage(NotSupportedError, 'BRIN option autosummarize requires PostgreSQL 10+.'): + with mock.patch('django.db.connection.features.has_brin_autosummarize', False): + with connection.schema_editor() as editor: + editor.add_index(CharFieldModel, index) + self.assertNotIn(index_name, self.get_constraints(CharFieldModel._meta.db_table)) + def test_btree_index(self): # Ensure the table is there and doesn't have an index. self.assertNotIn('field', self.get_constraints(CharFieldModel._meta.db_table))