From 2f19306a125a9253d99b35b276d932e8e24d4e6f Mon Sep 17 00:00:00 2001 From: Akshesh Date: Mon, 8 Aug 2016 10:29:08 +0530 Subject: [PATCH] Refs #27030 -- Added index type introspection on PostgreSQL. --- .../contrib/gis/db/backends/postgis/introspection.py | 10 ++++++---- django/db/backends/base/features.py | 3 +++ django/db/backends/postgresql/features.py | 1 + django/db/backends/postgresql/introspection.py | 8 ++++++-- tests/introspection/tests.py | 5 +++++ 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/django/contrib/gis/db/backends/postgis/introspection.py b/django/contrib/gis/db/backends/postgis/introspection.py index 71aa57f163d..e4579216f40 100644 --- a/django/contrib/gis/db/backends/postgis/introspection.py +++ b/django/contrib/gis/db/backends/postgis/introspection.py @@ -24,14 +24,16 @@ 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 - FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, - pg_catalog.pg_index idx, pg_catalog.pg_attribute attr - LEFT JOIN pg_catalog.pg_type t ON t.oid = attr.atttypid + SELECT DISTINCT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary, + am.amname + 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 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/base/features.py b/django/db/backends/base/features.py index e3677dd35af..67c34f028f8 100644 --- a/django/db/backends/base/features.py +++ b/django/db/backends/base/features.py @@ -163,6 +163,9 @@ class BaseDatabaseFeatures(object): # Can the backend introspect the column order (ASC/DESC) for indexes? supports_index_column_ordering = True + # Can the backend introspect the type of index created? + can_introspect_index_type = False + # Support for the DISTINCT ON clause can_distinct_on_fields = False diff --git a/django/db/backends/postgresql/features.py b/django/db/backends/postgresql/features.py index a9e1c77480a..918dfe79787 100644 --- a/django/db/backends/postgresql/features.py +++ b/django/db/backends/postgresql/features.py @@ -22,6 +22,7 @@ class DatabaseFeatures(BaseDatabaseFeatures): can_introspect_autofield = True can_introspect_ip_address_field = True can_introspect_small_integer_field = True + can_introspect_index_type = True can_distinct_on_fields = True can_rollback_ddl = True supports_combined_alters = True diff --git a/django/db/backends/postgresql/introspection.py b/django/db/backends/postgresql/introspection.py index 85ea66f6d1f..50c8fb11f04 100644 --- a/django/db/backends/postgresql/introspection.py +++ b/django/db/backends/postgresql/introspection.py @@ -36,13 +36,15 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): ignored_tables = [] _get_indexes_query = """ - SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary + SELECT attr.attname, idx.indkey, idx.indisunique, idx.indisprimary, + am.amname FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, - pg_catalog.pg_index idx, pg_catalog.pg_attribute attr + pg_catalog.pg_index idx, pg_catalog.pg_attribute attr, pg_catalog.pg_am am 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): @@ -132,6 +134,7 @@ 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 @@ -142,6 +145,7 @@ 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): diff --git a/tests/introspection/tests.py b/tests/introspection/tests.py index 31b02147042..f01f81e7183 100644 --- a/tests/introspection/tests.py +++ b/tests/introspection/tests.py @@ -170,6 +170,11 @@ 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):