From 4c7bf83cde9f698cad019a9b808dbe45a832d9c3 Mon Sep 17 00:00:00 2001 From: Akshesh Date: Thu, 25 Aug 2016 12:42:17 +0530 Subject: [PATCH] Refs #27097, #27098 -- Moved PostgreSQL index type introspection to get_constraints(). --- .../gis/db/backends/postgis/introspection.py | 6 ++---- django/db/backends/postgresql/introspection.py | 17 +++++++---------- tests/introspection/tests.py | 13 ++++++++----- tests/postgres_tests/test_indexes.py | 13 +++++++------ 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/django/contrib/gis/db/backends/postgis/introspection.py b/django/contrib/gis/db/backends/postgis/introspection.py index e4579216f4..5e7c34aeed 100644 --- a/django/contrib/gis/db/backends/postgis/introspection.py +++ b/django/contrib/gis/db/backends/postgis/introspection.py @@ -24,16 +24,14 @@ class PostGISIntrospection(DatabaseIntrospection): # expression over the raster column through the ST_ConvexHull function. # So the default query has to be adapted to include raster indices. _get_indexes_query = """ - SELECT DISTINCT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary, - am.amname + SELECT DISTINCT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index idx, - pg_catalog.pg_attribute attr, pg_catalog.pg_type t, pg_catalog.pg_am am + pg_catalog.pg_attribute attr, pg_catalog.pg_type t WHERE c.oid = idx.indrelid AND idx.indexrelid = c2.oid AND attr.attrelid = c.oid AND t.oid = attr.atttypid - AND c2.relam = am.oid AND ( attr.attnum = idx.indkey[0] OR (t.typname LIKE 'raster' AND idx.indkey = '0') diff --git a/django/db/backends/postgresql/introspection.py b/django/db/backends/postgresql/introspection.py index 50c8fb11f0..884270e534 100644 --- a/django/db/backends/postgresql/introspection.py +++ b/django/db/backends/postgresql/introspection.py @@ -36,15 +36,13 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): ignored_tables = [] _get_indexes_query = """ - SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary, - am.amname + SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, - pg_catalog.pg_index idx, pg_catalog.pg_attribute attr, pg_catalog.pg_am am + pg_catalog.pg_index idx, pg_catalog.pg_attribute attr WHERE c.oid = idx.indrelid AND idx.indexrelid = c2.oid AND attr.attrelid = c.oid AND attr.attnum = idx.indkey[0] - AND c2.relam = am.oid AND c.relname = %s""" def get_field_type(self, data_type, description): @@ -134,7 +132,6 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): # row[1] (idx.indkey) is stored in the DB as an array. It comes out as # a string of space-separated integers. This designates the field # indexes (1-based) of the fields that have indexes on the table. - # row[4] is the type of index, e.g. btree, hash, etc. # Here, we skip any indexes across multiple fields. if ' ' in row[1]: continue @@ -145,7 +142,6 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): indexes[row[0]]['primary_key'] = True if row[2]: indexes[row[0]]['unique'] = True - indexes[row[0]]['type'] = row[4] return indexes def get_constraints(self, cursor, table_name): @@ -216,10 +212,10 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): cursor.execute(""" SELECT indexname, array_agg(attname), indisunique, indisprimary, - array_agg(ordering) + array_agg(ordering), amname FROM ( SELECT - c2.relname as indexname, idx.*, attr.attname, + c2.relname as indexname, idx.*, attr.attname, am.amname, CASE WHEN am.amcanorder THEN CASE (option & 1) @@ -238,9 +234,9 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): AND c2.relam=am.oid AND c.relname = %s ) s2 - GROUP BY indexname, indisunique, indisprimary; + GROUP BY indexname, indisunique, indisprimary, amname;; """, [table_name]) - for index, columns, unique, primary, orders in cursor.fetchall(): + for index, columns, unique, primary, orders, type_ in cursor.fetchall(): if index not in constraints: constraints[index] = { "columns": columns, @@ -250,5 +246,6 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): "foreign_key": None, "check": False, "index": True, + "type": type_, } return constraints diff --git a/tests/introspection/tests.py b/tests/introspection/tests.py index 5e2d6f1c99..766e51dea7 100644 --- a/tests/introspection/tests.py +++ b/tests/introspection/tests.py @@ -172,11 +172,6 @@ class IntrospectionTests(TransactionTestCase): def test_get_indexes(self): with connection.cursor() as cursor: indexes = connection.introspection.get_indexes(cursor, Article._meta.db_table) - if connection.features.can_introspect_index_type: - index_type = indexes['reporter_id'].pop('type', None) - self.assertIsNotNone(index_type) - if connection.vendor == 'postgresql': - self.assertEqual(index_type, 'btree') self.assertEqual(indexes['reporter_id'], {'unique': False, 'primary_key': False}) def test_get_indexes_multicol(self): @@ -189,6 +184,14 @@ class IntrospectionTests(TransactionTestCase): self.assertNotIn('first_name', indexes) self.assertIn('id', indexes) + @skipUnlessDBFeature('can_introspect_index_type') + def test_get_constraints_index_types(self): + with connection.cursor() as cursor: + constraints = connection.introspection.get_constraints(cursor, Article._meta.db_table) + for key, val in constraints.items(): + if val['index'] and not (val['primary_key'] or val['unique']): + self.assertEqual(val['type'], 'btree') + @skipUnlessDBFeature('supports_index_column_ordering') def test_get_constraints_indexes_orders(self): """ diff --git a/tests/postgres_tests/test_indexes.py b/tests/postgres_tests/test_indexes.py index 41bdd3beca..8c15f01d47 100644 --- a/tests/postgres_tests/test_indexes.py +++ b/tests/postgres_tests/test_indexes.py @@ -33,23 +33,24 @@ class GinIndexTests(PostgreSQLTestCase): class SchemaTests(PostgreSQLTestCase): - def get_indexes(self, table): + def get_constraints(self, table): """ Get the indexes on the table using a new cursor. """ with connection.cursor() as cursor: - return connection.introspection.get_indexes(cursor, table) + return connection.introspection.get_constraints(cursor, table) def test_gin_index(self): # Ensure the table is there and doesn't have an index. - self.assertNotIn('field', self.get_indexes(IntegerArrayModel._meta.db_table)) + self.assertNotIn('field', self.get_constraints(IntegerArrayModel._meta.db_table)) # Add the index index = GinIndex(fields=['field'], name='integer_array_model_field_gin') with connection.schema_editor() as editor: editor.add_index(IntegerArrayModel, index) - self.assertIn('field', self.get_indexes(IntegerArrayModel._meta.db_table)) - self.assertEqual(self.get_indexes(IntegerArrayModel._meta.db_table)['field']['type'], 'gin') + self.assertIn('integer_array_model_field_gin', self.get_constraints(IntegerArrayModel._meta.db_table)) + constraints = self.get_constraints(IntegerArrayModel._meta.db_table) + self.assertEqual(constraints['integer_array_model_field_gin']['type'], 'gin') # Drop the index with connection.schema_editor() as editor: editor.remove_index(IntegerArrayModel, index) - self.assertNotIn('field', self.get_indexes(IntegerArrayModel._meta.db_table)) + self.assertNotIn('integer_array_model_field_gin', self.get_constraints(IntegerArrayModel._meta.db_table))