]> granicus.if.org Git - postgresql/commitdiff
Fix errors in key_column_usage.position_in_unique_constraint column recently
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 10 Nov 2006 18:10:10 +0000 (18:10 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 10 Nov 2006 18:10:10 +0000 (18:10 +0000)
added to information_schema (per a SQL2003 addition).  The original coding
failed if a referenced column participated in more than one pg_constraint
entry.  Also, it did not work if an FK relied directly on a unique index
without any constraint syntactic sugar --- this case is outside the SQL spec,
but PG has always supported it, so it's reasonable for our information_schema
to handle it too.  Per bug#2750 from Stephen Haberman.

Although this patch changes the initial catalog contents, I didn't force
initdb.  Any beta3 testers who need the fix can install it via CREATE OR
REPLACE VIEW, so forcing them to initdb seems an unnecessary imposition.

src/backend/catalog/information_schema.sql

index ea0601f464c3bc8adef7d6963b4f1159b384a4e4..092283250a56c542fee16258b00d78da3a4833b4 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2003-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.37 2006/09/14 22:05:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.38 2006/11/10 18:10:10 tgl Exp $
  */
 
 /*
@@ -52,6 +52,28 @@ CREATE FUNCTION _pg_keysequal(smallint[], smallint[]) RETURNS boolean
     RETURNS NULL ON NULL INPUT
     AS 'select information_schema._pg_keyissubset($1, $2) and information_schema._pg_keyissubset($2, $1)';
 
+/* Get the OID of the unique index that an FK constraint depends on */
+CREATE FUNCTION _pg_underlying_index(oid) RETURNS oid
+    LANGUAGE sql STRICT STABLE
+    AS $$
+SELECT refobjid FROM pg_catalog.pg_depend
+  WHERE classid = 'pg_catalog.pg_constraint'::pg_catalog.regclass AND
+        objid = $1 AND
+        refclassid = 'pg_catalog.pg_class'::pg_catalog.regclass AND
+        refobjsubid = 0 AND deptype = 'n'
+$$;
+
+/* Given an index's OID and an underlying-table column number, return the
+ * column's position in the index (NULL if not there) */
+CREATE FUNCTION _pg_index_position(oid, smallint) RETURNS int
+    LANGUAGE sql STRICT STABLE
+    AS $$
+SELECT (ss.a).n FROM
+  (SELECT information_schema._pg_expandarray(indkey) AS a
+   FROM pg_catalog.pg_index WHERE indexrelid = $1) ss
+  WHERE (ss.a).x = $2;
+$$;
+
 CREATE FUNCTION _pg_truetypid(pg_attribute, pg_type) RETURNS oid
     LANGUAGE sql
     IMMUTABLE
@@ -922,17 +944,16 @@ CREATE VIEW key_column_usage AS
            CAST(relname AS sql_identifier) AS table_name,
            CAST(a.attname AS sql_identifier) AS column_name,
            CAST((ss.x).n AS cardinal_number) AS ordinal_position,
-           (
-             SELECT CAST(a AS cardinal_number)
-             FROM pg_constraint,
-               (SELECT a FROM generate_series(1, array_upper(ss.confkey,1)) a) AS foo
-             WHERE conrelid = ss.confrelid
-             AND conkey[foo.a] = ss.confkey[(ss.x).n]
-           ) AS position_in_unique_constraint
+           CAST(CASE WHEN contype = 'f' THEN
+                  _pg_index_position(_pg_underlying_index(ss.coid),
+                                     ss.confkey[(ss.x).n])
+                     ELSE NULL
+                END AS cardinal_number)
+             AS position_in_unique_constraint
     FROM pg_attribute a,
-         (SELECT r.oid, r.relname, nc.nspname AS nc_nspname,
+         (SELECT r.oid AS roid, r.relname, nc.nspname AS nc_nspname,
                  nr.nspname AS nr_nspname,
-                 c.conname, c.confkey, c.confrelid,
+                 c.oid AS coid, c.conname, c.contype, c.confkey, c.confrelid,
                  _pg_expandarray(c.conkey) AS x
           FROM pg_namespace nr, pg_class r, pg_namespace nc,
                pg_constraint c
@@ -947,7 +968,7 @@ CREATE VIEW key_column_usage AS
                      OR has_table_privilege(c.oid, 'INSERT')
                      OR has_table_privilege(c.oid, 'UPDATE')
                      OR has_table_privilege(c.oid, 'REFERENCES')) ) AS ss
-    WHERE ss.oid = a.attrelid
+    WHERE ss.roid = a.attrelid
           AND a.attnum = (ss.x).x
           AND NOT a.attisdropped;