Fixed #25476 -- Allowed PostgreSQL introspection to work regardless of table owner.

This commit is contained in:
Marcos Vives Del Sol 2016-08-22 19:06:56 +02:00 committed by Tim Graham
parent 8c054ed71d
commit d6b9aab37c
1 changed files with 34 additions and 56 deletions

View File

@ -149,65 +149,43 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
Retrieves any constraints or keys (unique, pk, fk, check, index) across one or more columns. Retrieves any constraints or keys (unique, pk, fk, check, index) across one or more columns.
""" """
constraints = {} constraints = {}
# Loop over the key table, collecting things as constraints # Loop over the key table, collecting things as constraints. The column
# This will get PKs, FKs, and uniques, but not CHECK # 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(""" cursor.execute("""
SELECT SELECT
kc.constraint_name, c.conname,
kc.column_name, array(
c.constraint_type, SELECT attname
array(SELECT table_name::text || '.' || column_name::text FROM (
FROM information_schema.constraint_column_usage SELECT unnest(c.conkey) AS colid,
WHERE constraint_name = kc.constraint_name) generate_series(1, array_length(c.conkey, 1)) AS arridx
FROM information_schema.key_column_usage AS kc ) AS cols
JOIN information_schema.table_constraints AS c ON JOIN pg_attribute AS ca ON cols.colid = ca.attnum
kc.table_schema = c.table_schema AND WHERE ca.attrelid = c.conrelid
kc.table_name = c.table_name AND ORDER BY cols.arridx
kc.constraint_name = c.constraint_name ),
WHERE c.contype,
kc.table_schema = %s AND (SELECT fkc.relname || '.' || fka.attname
kc.table_name = %s FROM pg_attribute AS fka
ORDER BY kc.ordinal_position ASC 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]) """, ["public", table_name])
for constraint, column, kind, used_cols in cursor.fetchall(): for constraint, columns, kind, used_cols in cursor.fetchall():
# If we're the first column, make the record constraints[constraint] = {
if constraint not in constraints: "columns": columns,
constraints[constraint] = { "primary_key": kind == "p",
"columns": [], "unique": kind in ["p", "u"],
"primary_key": kind.lower() == "primary key", "foreign_key": tuple(used_cols.split(".", 1)) if kind == "f" else None,
"unique": kind.lower() in ["primary key", "unique"], "check": kind == "c",
"foreign_key": tuple(used_cols[0].split(".", 1)) if kind.lower() == "foreign key" else None, "index": False,
"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)
# Now get indexes # Now get indexes
cursor.execute(""" cursor.execute("""
SELECT SELECT