summaryrefslogtreecommitdiff
path: root/django/db/backends/postgresql/introspection.py
diff options
context:
space:
mode:
authorNick Pope <nick.pope@flightdataservices.com>2018-09-12 01:23:35 +0100
committerTim Graham <timograham@gmail.com>2018-10-02 14:02:04 -0400
commitbf8b625a3bb6c2cb5f1be3713f3bafe2c1050366 (patch)
treebc5b93f5358016b15e7dd49ba2cb1f9002dea9d2 /django/db/backends/postgresql/introspection.py
parent45ef3df7d07489ee0b76479cc799faa92e443a69 (diff)
downloaddjango-bf8b625a3bb6c2cb5f1be3713f3bafe2c1050366.tar.gz
Refs #29722 -- Added introspection of materialized views for PostgreSQL.
Diffstat (limited to 'django/db/backends/postgresql/introspection.py')
-rw-r--r--django/db/backends/postgresql/introspection.py31
1 files changed, 20 insertions, 11 deletions
diff --git a/django/db/backends/postgresql/introspection.py b/django/db/backends/postgresql/introspection.py
index c20d7b659e..77db6d5cbf 100644
--- a/django/db/backends/postgresql/introspection.py
+++ b/django/db/backends/postgresql/introspection.py
@@ -44,11 +44,11 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
SELECT c.relname, c.relkind
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
- WHERE c.relkind IN ('f', 'r', 'v')
+ WHERE c.relkind IN ('f', 'm', 'r', 'v')
AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
AND pg_catalog.pg_table_is_visible(c.oid)
""")
- mapping = {'f': 't', 'r': 't', 'v': 'v'}
+ mapping = {'f': 't', 'm': 'v', 'r': 't', 'v': 'v'}
return [
TableInfo(row[0], mapping[row[1]])
for row in cursor.fetchall() if row[0] not in self.ignored_tables
@@ -59,18 +59,27 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
Return 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)
+ # Query the pg_catalog tables as cursor.description does not reliably
+ # return the nullable property and information_schema.columns does not
+ # contain details of materialized views.
cursor.execute("""
- SELECT column_name, is_nullable, column_default
- FROM information_schema.columns
- WHERE table_name = %s""", [table_name])
+ SELECT
+ a.attname AS column_name,
+ NOT (a.attnotnull OR (t.typtype = 'd' AND t.typnotnull)) AS is_nullable,
+ pg_get_expr(ad.adbin, ad.adrelid) AS column_default
+ FROM pg_attribute a
+ LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
+ JOIN pg_type t ON a.atttypid = t.oid
+ JOIN pg_class c ON a.attrelid = c.oid
+ JOIN pg_namespace n ON c.relnamespace = n.oid
+ WHERE c.relkind IN ('f', 'm', 'r', 'v')
+ AND c.relname = %s
+ AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
+ AND pg_catalog.pg_table_is_visible(c.oid)
+ """, [table_name])
field_map = {line[0]: line[1:] for line in cursor.fetchall()}
cursor.execute("SELECT * FROM %s LIMIT 1" % self.connection.ops.quote_name(table_name))
- return [
- FieldInfo(*line[0:6], field_map[line.name][0] == 'YES', field_map[line.name][1])
- for line in cursor.description
- ]
+ return [FieldInfo(*line[0:6], *field_map[line.name]) for line in cursor.description]
def get_sequences(self, cursor, table_name, table_fields=()):
cursor.execute("""