More information schema views.
authorPeter Eisentraut
Tue, 17 Jun 2003 18:00:48 +0000 (18:00 +0000)
committerPeter Eisentraut
Tue, 17 Jun 2003 18:00:48 +0000 (18:00 +0000)
doc/src/sgml/information_schema.sgml
src/backend/catalog/information_schema.sql

index 82760ecdc44d5d9a4fb0f78d6dabfa56dcfa6b3b..2d862623858d788e3ed6a876aa17f2ae296d1cfb 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
 
  The Information Schema
   
  
 
+  <literal>column_privileges</literal>
+
+  
+   The view column_privileges identifies all
+   privileges granted on columns to the current user or by the current
+   user.  There is one row for each combination of column, grantor,
+   and grantee.
+  
+
+  
+   In PostgreSQL, you can only grant privileges on entire tables, not
+   individual columns.  Therefore, this view contains the same
+   information as table_privileges, just
+   represented through one row for each column in each appropriate
+   table.  But if you want to make your applications fit for possible
+   future developements, it is generally the right choice to use this
+   view instead of table_privileges.
+  
+
+  
+   <literal>column_privileges</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      grantor
+      sql_identifier
+      Name of the user that granted the privilege
+     
+
+     
+      grantee
+      sql_identifier
+      Name of the user that the privilege was granted to
+     
+
+     
+      table_catalog
+      sql_identifier
+      Name of the database that contains the table that contains the column (always the current database)
+     
+
+     
+      table_schema
+      sql_identifier
+      Name of the schema that contains the table that contains the column
+     
+
+     
+      table_name
+      sql_identifier
+      Name of the table that contains the column
+     
+
+     
+      column_name
+      sql_identifier
+      Name of the column
+     
+
+     
+      privilege_type
+      character_data
+      
+       Type of the privilege: SELECT,
+       DELETEINSERT,
+       UPDATEREFERENCES, or
+       TRIGGER
+      
+     
+
+     
+      is_grantable
+      character_data
+      YES if the privilege is grantable, NO if not
+     
+    
+   
+  
+
+  <literal>column_udt_usage</literal>
+
+  
+   The view column_udt_usage identifies all columns
+   that use data types owned by the current user.  Note that in
+   PostgreSQL, built-in data types behave like user-defined types, so
+   they are included here as well.  See also 
+   linkend="infoschema-columns"> for details.
+  
+
+  
+   <literal>column_udt_usage</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      udt_catalog
+      sql_identifier
+      
+       Name of the database that the column data type (the underlying
+       type of the domain, if applicable) is defined in (always the
+       current database)
+      
+     
+
+     
+      udt_schema
+      sql_identifier
+      
+       Name of the schema that the column data type (the underlying
+       type of the domain, if applicable) is defined in
+      
+     
+
+     
+      udt_name
+      sql_identifier
+      
+       Name of the column data type (the underlying type of the
+       domain, if applicable)
+      
+     
+
+     
+      table_catalog
+      sql_identifier
+      Name of the database containing the table (always the current database)
+     
+
+     
+      table_schema
+      sql_identifier
+      Name of the schema containing the table
+     
+
+     
+      table_name
+      sql_identifier
+      Name of the table
+     
+
+     
+      column_name
+      sql_identifier
+      Name of the column
+     
+    
+   
+  
+
  
   <literal>columns</literal>
 
   
  
 
+  <literal>constraint_column_usage</literal>
+
+  
+   The view constraint_column_usage identifies all
+   columns in the current database that are used by some constraint.
+   Only those columns are shown that are contained in a table owned
+   the current user.  For a check constraint, this view identifies the
+   columns that are used in the check expression.  For a foreign key
+   constraint, this view identifies the columns that the foreign key
+   references.  For a unique or primary key constraint, this view
+   identifies the constrained columns.
+  
+
+  
+   <literal>constraint_column_usage</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      table_catalog
+      sql_identifier
+      
+       Name of the database that contains the table that contains the
+       column that is used by some constraint (always the current
+       database)
+      
+     
+
+     
+      table_schema
+      sql_identifier
+      
+       Name of the schema that contains the table that contains the
+       column that is used by some constraint
+      
+     
+
+     
+      table_name
+      sql_identifier
+      
+       Name of the table that contains the column that is used by some
+       constraint
+      
+     
+
+     
+      column_name
+      sql_identifier
+      
+       Name of the column that is used by some constraint
+      
+     
+
+     
+      constraint_catalog
+      sql_identifier
+      Name of the database that contains the constraint (always the current database)
+     
+
+     
+      constraint_schema
+      sql_identifier
+      Name of the schema that contains the constraint
+     
+
+     
+      constraint_name
+      sql_identifier
+      Name of the constraint
+     
+    
+   
+  
+
  
   <literal>constraint_table_usage</literal>
 
    table_constraints, which identifies all table
    constraints along with the table they are defined on.)  For a
    foreign key constraint, this view identifies the table that the
-   foreign key references.  Unique and primary key constraints simply
-   identify the table they belong to.  Check constraints and not-null
-   constraints are not included in this view.
+   foreign key references.  For a unique or primary key constraint,
+   this view simply identifies the table the constraint belongs to.
+   Check constraints and not-null constraints are not included in this
+   view.
   
 
   
   
  
 
+  <literal>domain_udt_usage</literal>
+
+  
+   The view domain_udt_usage identifies all columns
+   that use data types owned by the current user. Note that in
+   PostgreSQL, built-in data types behave like user-defined types, so
+   they are included here as well.
+  
+
+  
+   <literal>domain_udt_usage</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      udt_catalog
+      sql_identifier
+      Name of the database that the domain data type is defined in (always the current database)
+     
+
+     
+      udt_schema
+      sql_identifier
+      Name of the schema that the domain data type is defined in
+     
+
+     
+      udt_name
+      sql_identifier
+      Name of the domain data type
+     
+
+     
+      domain_catalog
+      sql_identifier
+      Name of the database that contains the domain (always the current database)
+     
+
+     
+      domain_schema
+      sql_identifier
+      Name of the schema that contains the domain
+     
+
+     
+      domain_name
+      sql_identifier
+      Name of the domain
+     
+    
+   
+  
+
  
   <literal>domains</literal>
 
       Default expression of the domain
      
 
-      
-      udt_catalog
+     
+      udt_catalog
+      sql_identifier
+      Name of the database that the domain data type is defined in (always the current database)
+     
+
+     
+      udt_schema
+      sql_identifier
+      Name of the schema that the domain data type is defined in
+     
+
+     
+      udt_name
+      sql_identifier
+      Name of the domain data type
+     
+
+     
+      scope_catalog
+      sql_identifier
+      Applies to a feature not available in PostgreSQL
+     
+
+     
+      scope_schema
+      sql_identifier
+      Applies to a feature not available in PostgreSQL
+     
+
+     
+      scope_name
+      sql_identifier
+      Applies to a feature not available in PostgreSQL
+     
+
+     
+      maximum_cardinality
+      cardinal_number
+      Applies to a feature not available in PostgreSQL
+     
+
+     
+      dtd_identifier
+      sql_identifier
+      
+       A unique identifier of the data type of the domain (The
+       specific format of the identifier is not defined and not
+       guaranteed to remain the same in future versions.)
+      
+     
+    
+   
+  
+
+  <literal>key_column_usage</literal>
+
+  
+   The view key_column_usage identifies all columns
+   in the current database that are restricted by some unique, primary
+   key, or foreign key constraint.  Check constraints are not included
+   in this view.  Only those columns are shown that are contained in a
+   table owned the current user.
+  
+
+  
+   <literal>key_column_usage</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      constraint_catalog
       sql_identifier
-      Name of the database that the domain data type is defined in (always the current database)
+      Name of the database that contains the constraint (always the current database)
      
 
      
-      udt_schema
+      constraint_schema
       sql_identifier
-      Name of the schema that the domain data type is defined in
+      Name of the schema that contains the constraint
      
 
      
-      udt_name
+      constraint_name
       sql_identifier
-      Name of the domain data type
+      Name of the constraint
      
 
      
-      scope_catalog
+      table_catalog
       sql_identifier
-      Applies to a feature not available in PostgreSQL
+      
+       Name of the database that contains the table that contains the
+       column that is restricted by some constraint (always the
+       current database)
+      
      
 
      
-      scope_schema
+      table_schema
       sql_identifier
-      Applies to a feature not available in PostgreSQL
+      
+       Name of the schema that contains the table that contains the
+       column that is restricted by some constraint
+      
      
 
      
-      scope_name
+      table_name
       sql_identifier
-      Applies to a feature not available in PostgreSQL
+      
+       Name of the table that contains the column that is restricted
+       by some constraint
+      
      
 
      
-      maximum_cardinality
-      cardinal_number
-      Applies to a feature not available in PostgreSQL
+      column_name
+      sql_identifier
+      
+       Name of the column that is restricted by some constraint
+      
      
 
      
-      dtd_identifier
-      sql_identifier
+      ordinal_position
+      cardinal_number
       
-       A unique identifier of the data type of the domain (The
-       specific format of the identifier is not defined and not
-       guaranteed to remain the same in future versions.)
+       Ordinal position of the column within the constraint key (count
+       starts at 1)
       
      
     
      
       grantor
       sql_identifier
-      Name of the user that granted the privileges
+      Name of the user that granted the privilege
      
 
      
      
       grantor
       sql_identifier
-      Name of the user that granted the privileges
+      Name of the user that granted the privilege
      
 
      
   
  
 
+  <literal>triggers</literal>
+
+  
+   The view triggers contains all triggers defined
+   in the current database that are owned by the current user.  (The
+   owner of the table is the owner of the trigger.)
+  
+
+  
+   <literal>triggers</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      trigger_catalog
+      sql_identifier
+      Name of the database that contains the trigger (always the current database)
+     
+
+     
+      trigger_schema
+      sql_identifier
+      Name of the schema that contains the trigger
+     
+
+     
+      trigger_name
+      sql_identifier
+      Name of the trigger
+     
+
+     
+      event_manipulation
+      character_data
+      
+       Event that fires the trigger (INSERT,
+       UPDATE, or DELETE)
+      
+     
+
+     
+      event_object_catalog
+      sql_identifier
+      
+       Name of the database that contains the table that the trigger
+       is defined on (always the current database)
+      
+     
+
+     
+      event_object_schema
+      sql_identifier
+      Name of the schema that contains the table that the trigger is defined on
+     
+
+     
+      event_object_name
+      sql_identifier
+      Name of the table that the trigger is defined on
+     
+
+     
+      action_order
+      cardinal_number
+      Not yet implemented
+     
+
+     
+      action_condition
+      character_data
+      Applies to a feature not available in PostgreSQL
+     
+
+     
+      action_statement
+      character_data
+      
+       Statement that is executed by the trigger (currently always
+       EXECUTE PROCEDURE
+       function(...))
+      
+     
+
+     
+      action_orientation
+      character_data
+      
+       Identifies whether the trigger fires once for each processed
+       row or once for each statement (ROW or
+       STATEMENT)
+      
+     
+
+     
+      condition_timing
+      character_data
+      
+       Time at which the trigger fires (BEFORE or
+       AFTER)
+      
+     
+
+     
+      condition_reference_old_table
+      sql_identifier
+      Applies to a feature not available in PostgreSQL
+     
+
+     
+      condition_reference_new_table
+      sql_identifier
+      Applies to a feature not available in PostgreSQL
+     
+    
+   
+  
+
+  
+   Triggers in PostgreSQL have two incompatibilities with the SQL
+   standard that affect the representation in the information schema.
+   First, trigger names are local to the table in PostgreSQL, rather
+   than independent schema objects.  Therefore there may be duplicate
+   trigger names defined in one schema, as long as they belong to
+   different tables.  (trigger_catalog and
+   trigger_schema are really the values pertaining
+   to the table that the trigger is defined on.)  Second, triggers can
+   be defined to fire on multiple events in PostgreSQL (e.g.,
+   ON INSERT OR UPDATE), whereas the SQL standard
+   only allows one.  If a trigger is defined to fire on multiple
+   events, it is represented as multiple rows in the information
+   schema, one for each type of event.  As a consequence of these two
+   issues, the primary key of the view triggers is
+   really (trigger_catalog, trigger_schema, trigger_name,
+   event_object_name, event_manipulation) instead of
+   (trigger_catalog, trigger_schema, trigger_name),
+   which is what the SQL standard specifies.  Nonetheless, if you
+   define your triggers in a manner that conforms with the SQL
+   standard (trigger names unique in the schema and only one event
+   type per trigger), this will not affect you.
+  
+
+  <literal>view_column_usage</literal>
+
+  
+   The view view_column_usage identifies all
+   columns that are used in the query expression of a view (the
+   SELECT statement that defines the view).  A
+   column is only included if the current user is the owner of the
+   table that contains the column.
+  
+
+  
+   
+    Columns of system tables are not included.  This should be fixed
+    sometime.
+   
+  
+
+  
+   <literal>view_column_usage</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      view_catalog
+      sql_identifier
+      Name of the database that contains the view (always the current database)
+     
+
+     
+      view_schema
+      sql_identifier
+      Name of the schema that contains the view
+     
+
+     
+      view_name
+      sql_identifier
+      Name of the view
+     
+
+     
+      table_catalog
+      sql_identifier
+      
+       Name of the database that contains the table that contains the
+       column that is used by the view (always the current database)
+      
+     
+
+     
+      table_schema
+      sql_identifier
+      
+       Name of the schema that contains the table that contains the
+       column that is used by the view
+      
+     
+
+     
+      table_name
+      sql_identifier
+      
+       Name of the table that contains the column that is used by the
+       view
+      
+     
+
+     
+      column_name
+      sql_identifier
+      Name of the column that is used by the view
+     
+    
+   
+  
+
+  <literal>view_table_usage</literal>
+
+  
+   The view view_table_usage identifies all tables
+   that are used in the query expression of a view (the
+   SELECT statement that defines the view).  A
+   table is only included if the current user is the owner of that
+   table.
+  
+
+  
+   
+    System tables are not included.  This should be fixed sometime.
+   
+  
+
+  
+   <literal>view_table_usage</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      view_catalog
+      sql_identifier
+      Name of the database that contains the view (always the current database)
+     
+
+     
+      view_schema
+      sql_identifier
+      Name of the schema that contains the view
+     
+
+     
+      view_name
+      sql_identifier
+      Name of the view
+     
+
+     
+      table_catalog
+      sql_identifier
+      
+       Name of the database that contains the table the table that is
+       used by the view (always the current database)
+      
+     
+
+     
+      table_schema
+      sql_identifier
+      
+       Name of the schema that contains the table that is used by the
+       view
+      
+     
+
+     
+      table_name
+      sql_identifier
+      
+       Name of the table that is used by the view
+      
+     
+    
+   
+  
+
  
   <literal>views</literal>
 
index 224e61f0686bb8e84aede500c0618e33dda2e756..f228e96e6b2587ba66c5a9a6948676d9d552bef2 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright 2002, PostgreSQL Global Development Group
  *
- * $Id: information_schema.sql,v 1.8 2003/06/11 09:23:55 petere Exp $
+ * $Id: information_schema.sql,v 1.9 2003/06/17 18:00:48 petere Exp $
  */
 
 
@@ -78,13 +78,14 @@ CREATE VIEW check_constraints AS
            CAST(con.consrc AS character_data) AS check_clause
     FROM pg_namespace rs,
          pg_constraint con
-           LEFT OUTER JOIN pg_class c on (c.oid = con.conrelid)
-           LEFT OUTER JOIN pg_type t on (t.oid = con.contypid),
+           LEFT OUTER JOIN pg_class c ON (c.oid = con.conrelid)
+           LEFT OUTER JOIN pg_type t ON (t.oid = con.contypid),
          pg_user u
     WHERE rs.oid = con.connamespace
           AND u.usesysid = coalesce(c.relowner, t.typowner)
           AND u.usename = current_user
-          AND con.contype = 'c';
+          AND con.contype = 'c'
+          AND c.relkind = 'r';
 
 GRANT SELECT ON check_constraints TO PUBLIC;
 
@@ -106,9 +107,15 @@ CREATE VIEW column_domain_usage AS
     FROM pg_type t, pg_namespace nt, pg_class c, pg_namespace nc,
          pg_attribute a, pg_user u
 
-    WHERE t.typnamespace = nt.oid AND t.typtype = 'd'
-          AND c.relnamespace = nc.oid AND a.attrelid = c.oid
-          AND a.atttypid = t.oid AND t.typowner = u.usesysid
+    WHERE t.typnamespace = nt.oid
+          AND c.relnamespace = nc.oid
+          AND a.attrelid = c.oid
+          AND a.atttypid = t.oid
+          AND t.typowner = u.usesysid
+          AND t.typtype = 'd'
+          AND c.relkind IN ('r', 'v')
+          AND a.attnum > 0
+          AND NOT a.attisdropped
           AND u.usename = current_user;
 
 GRANT SELECT ON column_domain_usage TO PUBLIC;
@@ -119,23 +126,70 @@ GRANT SELECT ON column_domain_usage TO PUBLIC;
  * COLUMN_PRIVILEGES
  */
 
--- PostgreSQL does not have column privileges, so this view is empty.
--- (Table privileges do not also count as column privileges.)
-
 CREATE VIEW column_privileges AS
-    SELECT CAST(null AS sql_identifier) AS grantor,
-           CAST(null AS sql_identifier) AS grantee,
-           CAST(null AS sql_identifier) AS table_catalog,
-           CAST(null AS sql_identifier) AS table_schema,
-           CAST(null AS sql_identifier) AS table_name,
-           CAST(null AS sql_identifier) AS column_name,
-           CAST(null AS character_data) AS privilege_type,
-           CAST(null AS character_data) AS is_grantable
-    WHERE false;
+    SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
+           CAST(u_grantee.usename AS sql_identifier) AS grantee,
+           CAST(current_database() AS sql_identifier) AS table_catalog,
+           CAST(nc.nspname AS sql_identifier) AS table_schema,
+           CAST(c.relname AS sql_identifier) AS table_name,
+           CAST(a.attname AS sql_identifier) AS column_name,
+           CAST(pr.type AS character_data) AS privilege_type,
+           CAST(
+             CASE WHEN aclcontains(c.relacl,
+                                   makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, pr.type, true))
+                  THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
+
+    FROM pg_attribute a,
+         pg_class c,
+         pg_namespace nc,
+         pg_user u_grantor,
+         (SELECT usesysid, usename FROM pg_user UNION SELECT 0, 'PUBLIC') AS u_grantee,
+         (SELECT 'SELECT' UNION SELECT 'DELETE' UNION SELECT 'INSERT' UNION SELECT 'UPDATE'
+          UNION SELECT 'REFERENCES' UNION SELECT 'TRIGGER') AS pr (type)
+
+    WHERE a.attrelid = c.oid
+          AND c.relnamespace = nc.oid
+          AND a.attnum > 0
+          AND NOT a.attisdropped
+          AND c.relkind IN ('r', 'v')
+          AND aclcontains(c.relacl,
+                          makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, pr.type, false))
+          AND (u_grantor.usename = current_user
+               OR u_grantee.usename = current_user
+               OR u_grantee.usename = 'PUBLIC');
 
 GRANT SELECT ON column_privileges TO PUBLIC;
 
 
+/*
+ * 20.17
+ * COLUMN_UDT_USAGE view
+ */
+
+CREATE VIEW column_udt_usage AS
+    SELECT CAST(current_database() AS sql_identifier) AS udt_catalog,
+           CAST(coalesce(nbt.nspname, nt.nspname) AS sql_identifier) AS udt_schema,
+           CAST(coalesce(bt.typname, t.typname) AS sql_identifier) AS udt_name,
+           CAST(current_database() AS sql_identifier) AS table_catalog,
+           CAST(nc.nspname AS sql_identifier) AS table_schema,
+           CAST(c.relname AS sql_identifier) AS table_name,
+           CAST(a.attname AS sql_identifier) AS column_name
+
+    FROM pg_attribute a, pg_class c, pg_namespace nc, pg_user u,
+         (pg_type t JOIN pg_namespace nt ON (t.typnamespace = nt.oid))
+           LEFT JOIN (pg_type bt JOIN pg_namespace nbt ON (bt.typnamespace = nbt.oid))
+           ON (t.typtype = 'd' AND t.typbasetype = bt.oid)
+
+    WHERE a.attrelid = c.oid
+          AND a.atttypid = t.oid
+          AND u.usesysid = coalesce(bt.typowner, t.typowner)
+          AND nc.oid = c.relnamespace
+          AND a.attnum > 0 AND NOT a.attisdropped AND c.relkind in ('r', 'v')
+          AND u.usename = current_user;
+
+GRANT SELECT ON column_udt_usage TO PUBLIC;
+
+
 /*
  * 20.18
  * COLUMNS view
@@ -305,9 +359,6 @@ GRANT SELECT ON columns TO PUBLIC;
  * CONSTRAINT_COLUMN_USAGE view
  */
 
--- FIXME: This only works for check constraints so far; for the others
--- we need a built-in way to convert arrays to virtual tables.
-
 CREATE VIEW constraint_column_usage AS
     SELECT CAST(current_database() AS sql_identifier) AS table_catalog,
            CAST(tblschema AS sql_identifier) AS table_schema,
@@ -318,6 +369,7 @@ CREATE VIEW constraint_column_usage AS
            CAST(cstrname AS sql_identifier) AS constraint_name
 
     FROM (
+        /* check constraints */
         SELECT DISTINCT nr.nspname, r.relname, r.relowner, a.attname, nc.nspname, c.conname
           FROM pg_namespace nr, pg_class r, pg_attribute a, pg_depend d, pg_namespace nc, pg_constraint c
           WHERE nr.oid = r.relnamespace
@@ -329,6 +381,33 @@ CREATE VIEW constraint_column_usage AS
             AND d.objid = c.oid
             AND c.connamespace = nc.oid
             AND c.contype = 'c'
+            AND r.relkind = 'r'
+            AND a.attnum > 0
+            AND NOT a.attisdropped
+
+        UNION
+
+        /* unique/primary key/foreign key constraints */
+        SELECT nr.nspname, r.relname, r.relowner, a.attname, nc.nspname, c.conname
+          FROM pg_namespace nr, pg_class r, pg_attribute a, pg_namespace nc, pg_constraint c,
+            (select 1 union select 2 union select 3 union select 4 union select 5 union
+             select 6 union select 7 union select 8 union select 9 union select 10 union
+             select 11 union select 12 union select 13 union select 14 union select 15 union
+             select 16 union select 17 union select 18 union select 19 union select 20 union
+             select 21 union select 22 union select 23 union select 24 union select 25 union
+             select 26 union select 27 union select 28 union select 29 union select 30 union
+             select 31 union select 32) AS pos(n)
+          WHERE nr.oid = r.relnamespace
+            AND r.oid = a.attrelid
+            AND r.oid = c.conrelid
+            AND nc.oid = c.connamespace
+            AND (CASE WHEN c.contype = 'f' THEN c.confkey[pos.n] = a.attnum
+                      ELSE c.conkey[pos.n] = a.attnum END)
+            AND a.attnum > 0
+            AND NOT a.attisdropped
+            AND c.contype IN ('p', 'u', 'f')
+            AND r.relkind = 'r'
+
       ) AS x (tblschema, tblname, tblowner, colname, cstrschema, cstrname),
       pg_user u
 
@@ -357,6 +436,7 @@ CREATE VIEW constraint_table_usage AS
     WHERE c.connamespace = nc.oid AND r.relnamespace = nr.oid
           AND ( (c.contype = 'f' AND c.confrelid = r.oid)
              OR (c.contype IN ('p', 'u') AND c.conrelid = r.oid) )
+          AND r.relkind = 'r'
           AND r.relowner = u.usesysid AND u.usename = current_user;
 
 GRANT SELECT ON constraint_table_usage TO PUBLIC;
@@ -388,6 +468,33 @@ CREATE VIEW domain_constraints AS
 GRANT SELECT ON domain_constraints TO PUBLIC;
 
 
+/*
+ * 20.25
+ * DOMAIN_UDT_USAGE view
+ */
+
+CREATE VIEW domain_udt_usage AS
+    SELECT CAST(current_database() AS sql_identifier) AS udt_catalog,
+           CAST(nbt.nspname AS sql_identifier) AS udt_schema,
+           CAST(bt.typname AS sql_identifier) AS udt_name,
+           CAST(current_database() AS sql_identifier) AS domain_catalog,
+           CAST(nt.nspname AS sql_identifier) AS domain_schema,
+           CAST(t.typname AS sql_identifier) AS domain_name
+
+    FROM pg_type t, pg_namespace nt,
+         pg_type bt, pg_namespace nbt,
+         pg_user u
+
+    WHERE t.typnamespace = nt.oid
+          AND t.typbasetype = bt.oid
+          AND bt.typnamespace = nbt.oid
+          AND t.typtype = 'd'
+          AND bt.typowner = u.usesysid
+          AND u.usename = current_user;
+
+GRANT SELECT ON domain_udt_usage TO PUBLIC;
+
+
 /*
  * 20.26
  * DOMAINS view
@@ -487,6 +594,46 @@ CREATE VIEW domains AS
 GRANT SELECT ON domains TO PUBLIC;
 
 
+/*
+ * 20.30
+ * KEY_COLUMN_USAGE view
+ */
+
+CREATE VIEW key_column_usage AS
+    SELECT CAST(current_database() AS sql_identifier) AS constraint_catalog,
+           CAST(nc.nspname AS sql_identifier) AS constraint_schema,
+           CAST(c.conname AS sql_identifier) AS constraint_name,
+           CAST(current_database() AS sql_identifier) AS table_catalog,
+           CAST(nr.nspname AS sql_identifier) AS table_schema,
+           CAST(r.relname AS sql_identifier) AS table_name,
+           CAST(a.attname AS sql_identifier) AS column_name,
+           CAST(pos.n AS cardinal_number) AS ordinal_position
+
+    FROM pg_namespace nr, pg_class r, pg_attribute a, pg_namespace nc, pg_constraint c,
+         pg_user u,
+         (select 1 union select 2 union select 3 union select 4 union select 5 union
+          select 6 union select 7 union select 8 union select 9 union select 10 union
+          select 11 union select 12 union select 13 union select 14 union select 15 union
+          select 16 union select 17 union select 18 union select 19 union select 20 union
+          select 21 union select 22 union select 23 union select 24 union select 25 union
+          select 26 union select 27 union select 28 union select 29 union select 30 union
+          select 31 union select 32) AS pos(n)
+
+    WHERE nr.oid = r.relnamespace
+          AND r.oid = a.attrelid
+          AND r.oid = c.conrelid
+          AND nc.oid = c.connamespace
+          AND c.conkey[pos.n] = a.attnum
+          AND a.attnum > 0
+          AND NOT a.attisdropped
+          AND c.contype IN ('p', 'u', 'f')
+          AND r.relkind = 'r'
+          AND r.relowner = u.usesysid
+          AND u.usename = current_user;
+
+GRANT SELECT ON key_column_usage TO PUBLIC;
+
+
 /*
  * 20.33
  * PARAMETERS view
@@ -593,6 +740,7 @@ CREATE VIEW referential_constraints AS
           AND con.confkey = pkc.conkey
           AND pkc.connamespace = npkc.oid
           AND c.relowner = u.usesysid
+          AND c.relkind = 'r'
           AND u.usename = current_user;
 
 GRANT SELECT ON referential_constraints TO PUBLIC;
@@ -932,6 +1080,7 @@ CREATE VIEW table_constraints AS
 
     WHERE nc.oid = c.connamespace AND nr.oid = r.relnamespace
           AND c.conrelid = r.oid AND r.relowner = u.usesysid
+          AND r.relkind = 'r'
           AND u.usename = current_user;
 
 -- FIMXE: Not-null constraints are missing here.
@@ -965,6 +1114,7 @@ CREATE VIEW table_privileges AS
           UNION SELECT 'REFERENCES' UNION SELECT 'TRIGGER') AS pr (type)
 
     WHERE c.relnamespace = nc.oid
+          AND c.relkind IN ('r', 'v')
           AND aclcontains(c.relacl,
                           makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, pr.type, false))
           AND (u_grantor.usename = current_user
@@ -1014,6 +1164,68 @@ CREATE VIEW tables AS
 GRANT SELECT ON tables TO PUBLIC;
 
 
+/*
+ * 20.59
+ * TRIGGERED_UPDATE_COLUMNS view
+ */
+
+-- PostgreSQL doesn't allow the specification of individual triggered
+-- update columns, so this view is empty.
+
+CREATE VIEW triggered_update_columns AS
+    SELECT CAST(current_database() AS sql_identifier) AS trigger_catalog,
+           CAST(null AS sql_identifier) AS trigger_schema,
+           CAST(null AS sql_identifier) AS trigger_name,
+           CAST(current_database() AS sql_identifier) AS event_object_catalog,
+           CAST(null AS sql_identifier) AS event_object_schema,
+           CAST(null AS sql_identifier) AS event_object_table,
+           CAST(null AS sql_identifier) AS event_object_column
+    WHERE false;
+
+GRANT SELECT ON triggered_update_columns TO PUBLIC;
+
+
+/*
+ * 20.62
+ * TRIGGERS view
+ */
+
+CREATE VIEW triggers AS
+    SELECT CAST(current_database() AS sql_identifier) AS trigger_catalog,
+           CAST(n.nspname AS sql_identifier) AS trigger_schema,
+           CAST(t.tgname AS sql_identifier) AS trigger_name,
+           CAST(em.text AS character_data) AS event_manipulation,
+           CAST(current_database() AS sql_identifier) AS event_object_catalog,
+           CAST(n.nspname AS sql_identifier) AS event_object_schema,
+           CAST(c.relname AS sql_identifier) AS event_object_table,
+           CAST(null AS cardinal_number) AS action_order,
+           CAST(null AS character_data) AS action_condition,
+           CAST(
+             substring(pg_get_triggerdef(t.oid) from
+                       position('EXECUTE PROCEDURE' in substring(pg_get_triggerdef(t.oid) from 48)) + 47)
+             AS character_data) AS action_statement,
+           CAST(
+             CASE WHEN t.tgtype & 1 = 1 THEN 'ROW' ELSE 'STATEMENT' END
+             AS character_data) AS action_orientation,
+           CAST(
+             CASE WHEN t.tgtype & 2 = 2 THEN 'BEFORE' ELSE 'AFTER' END
+             AS character_data) AS condition_timing,
+           CAST(null AS sql_identifier) AS condition_reference_old_table,
+           CAST(null AS sql_identifier) AS condition_reference_new_table
+
+    FROM pg_namespace n, pg_class c, pg_trigger t, pg_user u,
+         (SELECT 4, 'INSERT' UNION SELECT 8, 'DELETE' UNION SELECT 16, 'UPDATE') AS em (num, text)
+
+    WHERE n.oid = c.relnamespace
+          AND c.oid = t.tgrelid
+          AND c.relowner = u.usesysid
+          AND t.tgtype & em.num <> 0
+          AND NOT t.tgisconstraint
+          AND u.usename = current_user;
+
+GRANT SELECT ON triggers TO PUBLIC;
+
+
 /*
  * 20.63
  * USAGE_PRIVILEGES view
@@ -1044,6 +1256,81 @@ CREATE VIEW usage_privileges AS
 GRANT SELECT ON usage_privileges TO PUBLIC;
 
 
+/*
+ * 20.65
+ * VIEW_COLUMN_USAGE
+ */
+
+CREATE VIEW view_column_usage AS
+    SELECT DISTINCT
+           CAST(current_database() AS sql_identifier) AS view_catalog,
+           CAST(nv.nspname AS sql_identifier) AS view_schema,
+           CAST(v.relname AS sql_identifier) AS view_name,
+           CAST(current_database() AS sql_identifier) AS table_catalog,
+           CAST(nt.nspname AS sql_identifier) AS table_schema,
+           CAST(t.relname AS sql_identifier) AS table_name,
+           CAST(a.attname AS sql_identifier) AS column_name
+
+    FROM pg_user, pg_namespace nv, pg_class v, pg_depend dv,
+         pg_depend dt, pg_class t, pg_namespace nt,
+         pg_attribute a, pg_user u
+
+    WHERE nv.oid = v.relnamespace
+          AND v.relkind = 'v'
+          AND v.oid = dv.refobjid
+          AND dv.refclassid = (SELECT oid FROM pg_class WHERE relname = 'pg_class')
+          AND dv.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_rewrite')
+          AND dv.deptype = 'i'
+          AND dv.objid = dt.objid
+          AND dv.refobjid <> dt.refobjid
+          AND dt.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_rewrite')
+          AND dt.refclassid = (SELECT oid FROM pg_class WHERE relname = 'pg_class')
+          AND dt.refobjid = t.oid
+          AND t.relnamespace = nt.oid
+          AND t.relkind IN ('r', 'v')
+          AND t.oid = a.attrelid
+          AND dt.refobjsubid = a.attnum
+          AND t.relowner = u.usesysid AND u.usename = current_user;
+
+GRANT SELECT ON view_column_usage TO PUBLIC;
+
+
+/*
+ * 20.66
+ * VIEW_TABLE_USAGE
+ */
+
+CREATE VIEW view_table_usage AS
+    SELECT DISTINCT
+           CAST(current_database() AS sql_identifier) AS view_catalog,
+           CAST(nv.nspname AS sql_identifier) AS view_schema,
+           CAST(v.relname AS sql_identifier) AS view_name,
+           CAST(current_database() AS sql_identifier) AS table_catalog,
+           CAST(nt.nspname AS sql_identifier) AS table_schema,
+           CAST(t.relname AS sql_identifier) AS table_name
+
+    FROM pg_user, pg_namespace nv, pg_class v, pg_depend dv,
+         pg_depend dt, pg_class t, pg_namespace nt,
+         pg_user u
+
+    WHERE nv.oid = v.relnamespace
+          AND v.relkind = 'v'
+          AND v.oid = dv.refobjid
+          AND dv.refclassid = (SELECT oid FROM pg_class WHERE relname = 'pg_class')
+          AND dv.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_rewrite')
+          AND dv.deptype = 'i'
+          AND dv.objid = dt.objid
+          AND dv.refobjid <> dt.refobjid
+          AND dt.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_rewrite')
+          AND dt.refclassid = (SELECT oid FROM pg_class WHERE relname = 'pg_class')
+          AND dt.refobjid = t.oid
+          AND t.relnamespace = nt.oid
+          AND t.relkind IN ('r', 'v')
+          AND t.relowner = u.usesysid AND u.usename = current_user;
+
+GRANT SELECT ON view_table_usage TO PUBLIC;
+
+
 /*
  * 20.68
  * VIEWS view