mirror of
https://github.com/django/django.git
synced 2025-08-03 18:38:50 +00:00

Fixed #15933, #18082 -- the get_indexes() method introspection was done inconsitently depending on the backend. For example SQLite included all the columns in the table in the returned dictionary, while MySQL introspected also multicolumn indexes. All backends return now consistenly only single-column indexes. Thanks to andi for the MySQL report, and ikelly for comments on Oracle's get_indexes() changes.
88 lines
3.7 KiB
Python
88 lines
3.7 KiB
Python
from django.db.backends import BaseDatabaseIntrospection
|
|
|
|
|
|
class DatabaseIntrospection(BaseDatabaseIntrospection):
|
|
# Maps type codes to Django Field types.
|
|
data_types_reverse = {
|
|
16: 'BooleanField',
|
|
20: 'BigIntegerField',
|
|
21: 'SmallIntegerField',
|
|
23: 'IntegerField',
|
|
25: 'TextField',
|
|
700: 'FloatField',
|
|
701: 'FloatField',
|
|
869: 'GenericIPAddressField',
|
|
1042: 'CharField', # blank-padded
|
|
1043: 'CharField',
|
|
1082: 'DateField',
|
|
1083: 'TimeField',
|
|
1114: 'DateTimeField',
|
|
1184: 'DateTimeField',
|
|
1266: 'TimeField',
|
|
1700: 'DecimalField',
|
|
}
|
|
|
|
def get_table_list(self, cursor):
|
|
"Returns a list of table names in the current database."
|
|
cursor.execute("""
|
|
SELECT c.relname
|
|
FROM pg_catalog.pg_class c
|
|
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
WHERE c.relkind IN ('r', 'v', '')
|
|
AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
|
|
AND pg_catalog.pg_table_is_visible(c.oid)""")
|
|
return [row[0] for row in cursor.fetchall()]
|
|
|
|
def get_table_description(self, cursor, table_name):
|
|
"Returns a description of the table, with the DB-API cursor.description interface."
|
|
# As cursor.description does not return reliably the nullable property,
|
|
# we have to query the information_schema (#7783)
|
|
cursor.execute("""
|
|
SELECT column_name, is_nullable
|
|
FROM information_schema.columns
|
|
WHERE table_name = %s""", [table_name])
|
|
null_map = dict(cursor.fetchall())
|
|
cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
|
|
return [tuple([item for item in line[:6]] + [null_map[line[0]]==u'YES'])
|
|
for line in cursor.description]
|
|
|
|
def get_relations(self, cursor, table_name):
|
|
"""
|
|
Returns a dictionary of {field_index: (field_index_other_table, other_table)}
|
|
representing all relationships to the given table. Indexes are 0-based.
|
|
"""
|
|
cursor.execute("""
|
|
SELECT con.conkey, con.confkey, c2.relname
|
|
FROM pg_constraint con, pg_class c1, pg_class c2
|
|
WHERE c1.oid = con.conrelid
|
|
AND c2.oid = con.confrelid
|
|
AND c1.relname = %s
|
|
AND con.contype = 'f'""", [table_name])
|
|
relations = {}
|
|
for row in cursor.fetchall():
|
|
# row[0] and row[1] are single-item lists, so grab the single item.
|
|
relations[row[0][0] - 1] = (row[1][0] - 1, row[2])
|
|
return relations
|
|
|
|
def get_indexes(self, cursor, table_name):
|
|
# This query retrieves each index on the given table, including the
|
|
# first associated field name
|
|
cursor.execute("""
|
|
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
|
|
WHERE c.oid = idx.indrelid
|
|
AND idx.indexrelid = c2.oid
|
|
AND attr.attrelid = c.oid
|
|
AND attr.attnum = idx.indkey[0]
|
|
AND c.relname = %s""", [table_name])
|
|
indexes = {}
|
|
for row in cursor.fetchall():
|
|
# 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.
|
|
# Here, we skip any indexes across multiple fields.
|
|
if ' ' in row[1]:
|
|
continue
|
|
indexes[row[0]] = {'primary_key': row[3], 'unique': row[2]}
|
|
return indexes
|