From f3f9d03edf17ccfa17263c7efa0b1350d1ac9278 Mon Sep 17 00:00:00 2001 From: Haolun Chai Date: Sun, 14 Aug 2022 05:12:56 -0400 Subject: [PATCH] Fixed #33901 -- Skipped varchar_pattern_ops/text_pattern_ops index creation when db_collation is set. --- django/db/backends/postgresql/schema.py | 4 +++ tests/schema/tests.py | 36 +++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/django/db/backends/postgresql/schema.py b/django/db/backends/postgresql/schema.py index 3d4ddeeb6d..633146a80b 100644 --- a/django/db/backends/postgresql/schema.py +++ b/django/db/backends/postgresql/schema.py @@ -96,6 +96,10 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): # and text[size], so skip them. if "[" in db_type: return None + # Non-deterministic collations on Postgresql don't support indexes + # for operator classes varchar_pattern_ops/text_pattern_ops. + if getattr(field, "db_collation", None): + return None if db_type.startswith("varchar"): return self._create_index_sql( model, diff --git a/tests/schema/tests.py b/tests/schema/tests.py index 6fe35e7109..9e2385f5d8 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -1321,6 +1321,42 @@ class SchemaTests(TransactionTestCase): cs_collation, ) + @isolate_apps("schema") + @unittest.skipUnless(connection.vendor == "postgresql", "PostgreSQL specific") + @skipUnlessDBFeature( + "supports_collation_on_charfield", + "supports_non_deterministic_collations", + ) + def test_unique_with_collation_charfield(self): + ci_collation = "case_insensitive" + + def drop_collation(): + with connection.cursor() as cursor: + cursor.execute(f"DROP COLLATION IF EXISTS {ci_collation}") + + with connection.cursor() as cursor: + cursor.execute( + f"CREATE COLLATION IF NOT EXISTS {ci_collation} (provider = icu, " + f"locale = 'und-u-ks-level2', deterministic = false)" + ) + self.addCleanup(drop_collation) + + class CiCharModel(Model): + field = CharField(max_length=16, db_collation=ci_collation, unique=True) + + class Meta: + app_label = "schema" + + # Create the table. + with connection.schema_editor() as editor: + editor.create_model(CiCharModel) + self.isolated_local_models = [CiCharModel] + self.assertEqual( + self.get_column_collation(CiCharModel._meta.db_table, "field"), + ci_collation, + ) + self.assertIn("field", self.get_uniques(CiCharModel._meta.db_table)) + def test_alter_textfield_to_null(self): """ #24307 - Should skip an alter statement on databases with