summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcos Vives Del Sol <socram8888@gmail.com>2016-08-22 19:06:56 +0200
committerTim Graham <timograham@gmail.com>2016-09-02 20:11:23 -0400
commitd6b9aab37c41a772e5519e46b42b39958f99cadd (patch)
tree1b5d4c60da1ea0b1c5399239c9c032d3c75d76dc
parent8c054ed71d579aef53e074fcdaea56f110f1764e (diff)
downloaddjango-d6b9aab37c41a772e5519e46b42b39958f99cadd.tar.gz
Fixed #25476 -- Allowed PostgreSQL introspection to work regardless of table owner.
-rw-r--r--django/db/backends/postgresql/introspection.py90
1 files changed, 34 insertions, 56 deletions
diff --git a/django/db/backends/postgresql/introspection.py b/django/db/backends/postgresql/introspection.py
index eab1d4b4d7..8a8465d443 100644
--- a/django/db/backends/postgresql/introspection.py
+++ b/django/db/backends/postgresql/introspection.py
@@ -149,65 +149,43 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
Retrieves any constraints or keys (unique, pk, fk, check, index) across one or more columns.
"""
constraints = {}
- # Loop over the key table, collecting things as constraints
- # This will get PKs, FKs, and uniques, but not CHECK
+ # Loop over the key table, collecting things as constraints. The column
+ # array must return column names in the same order in which they were
+ # created.
+ # The subquery containing generate_series can be replaced with
+ # "WITH ORDINALITY" when support for PostgreSQL 9.3 is dropped.
cursor.execute("""
SELECT
- kc.constraint_name,
- kc.column_name,
- c.constraint_type,
- array(SELECT table_name::text || '.' || column_name::text
- FROM information_schema.constraint_column_usage
- WHERE constraint_name = kc.constraint_name)
- FROM information_schema.key_column_usage AS kc
- JOIN information_schema.table_constraints AS c ON
- kc.table_schema = c.table_schema AND
- kc.table_name = c.table_name AND
- kc.constraint_name = c.constraint_name
- WHERE
- kc.table_schema = %s AND
- kc.table_name = %s
- ORDER BY kc.ordinal_position ASC
+ c.conname,
+ array(
+ SELECT attname
+ FROM (
+ SELECT unnest(c.conkey) AS colid,
+ generate_series(1, array_length(c.conkey, 1)) AS arridx
+ ) AS cols
+ JOIN pg_attribute AS ca ON cols.colid = ca.attnum
+ WHERE ca.attrelid = c.conrelid
+ ORDER BY cols.arridx
+ ),
+ c.contype,
+ (SELECT fkc.relname || '.' || fka.attname
+ FROM pg_attribute AS fka
+ JOIN pg_class AS fkc ON fka.attrelid = fkc.oid
+ WHERE fka.attrelid = c.confrelid AND fka.attnum = c.confkey[1])
+ FROM pg_constraint AS c
+ JOIN pg_class AS cl ON c.conrelid = cl.oid
+ JOIN pg_namespace AS ns ON cl.relnamespace = ns.oid
+ WHERE ns.nspname = %s AND cl.relname = %s
""", ["public", table_name])
- for constraint, column, kind, used_cols in cursor.fetchall():
- # If we're the first column, make the record
- if constraint not in constraints:
- constraints[constraint] = {
- "columns": [],
- "primary_key": kind.lower() == "primary key",
- "unique": kind.lower() in ["primary key", "unique"],
- "foreign_key": tuple(used_cols[0].split(".", 1)) if kind.lower() == "foreign key" else None,
- "check": False,
- "index": False,
- }
- # Record the details
- constraints[constraint]['columns'].append(column)
- # Now get CHECK constraint columns
- cursor.execute("""
- SELECT kc.constraint_name, kc.column_name
- FROM information_schema.constraint_column_usage AS kc
- JOIN information_schema.table_constraints AS c ON
- kc.table_schema = c.table_schema AND
- kc.table_name = c.table_name AND
- kc.constraint_name = c.constraint_name
- WHERE
- c.constraint_type = 'CHECK' AND
- kc.table_schema = %s AND
- kc.table_name = %s
- """, ["public", table_name])
- for constraint, column in cursor.fetchall():
- # If we're the first column, make the record
- if constraint not in constraints:
- constraints[constraint] = {
- "columns": [],
- "primary_key": False,
- "unique": False,
- "foreign_key": None,
- "check": True,
- "index": False,
- }
- # Record the details
- constraints[constraint]['columns'].append(column)
+ for constraint, columns, kind, used_cols in cursor.fetchall():
+ constraints[constraint] = {
+ "columns": columns,
+ "primary_key": kind == "p",
+ "unique": kind in ["p", "u"],
+ "foreign_key": tuple(used_cols.split(".", 1)) if kind == "f" else None,
+ "check": kind == "c",
+ "index": False,
+ }
# Now get indexes
cursor.execute("""
SELECT