Information schema views for group privileges, some corrections on column
authorPeter Eisentraut
Sun, 29 Jun 2003 15:14:41 +0000 (15:14 +0000)
committerPeter Eisentraut
Sun, 29 Jun 2003 15:14:41 +0000 (15:14 +0000)
privileges.

doc/src/sgml/information_schema.sgml
src/backend/catalog/information_schema.sql

index 3936cdec490e18a6195f9997050e80aeef28e2e2..fb04ea8825f3b2ed3d2b56d0d110aac01148fa1b 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
 
  The Information Schema
   
  
 
+  <literal>applicable_roles</literal>
+
+  
+   The view applicable_roles identifies all groups
+   that the current user is a member of.  (A role is the same thing as
+   a group.)  Generally, it is better to use the view
+   enabled_roles instead of this one; see also
+   there.
+  
+
+  
+   <literal>applicable_roles</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      grantee
+      sql_identifier
+      Always the name of the current user
+     
+
+     
+      role_name
+      sql_identifier
+      Name of a group
+     
+
+     
+      is_grantable
+      character_data
+      Applies to a feature not available in PostgreSQL
+     
+    
+   
+  
+
  
   <literal>check_constraints</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.
+   and grantee.  Privileges granted to groups are identified in the
+   view role_column_grants.
   
 
   
    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.
+   table, but it only convers privilege types where column granularity
+   is possible: SELECTINSERT,
+   UPDATEREFERENCES.  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 if one of those
+   privilege types is concerned.
   
 
   
      
       grantee
       sql_identifier
-      Name of the user that the privilege was granted to
+      Name of the user or group that the privilege was granted to
      
 
      
       character_data
       
        Type of the privilege: SELECT,
-       DELETEINSERT,
-       UPDATEREFERENCES, or
-       TRIGGER
+       INSERTUPDATE, or
+       REFERENCES
       
      
 
     
    
   
+
+  
+   Note that the column grantee makes no
+   distinction between users and groups.  If you have users and groups
+   with the same name, there is unfortunately no way to distinguish
+   them.  A future version of PostgreSQL will possibly prohibit having
+   users and groups with the same name.
+  
  
 
  
@@ -1627,6 +1685,42 @@ ORDER BY c.ordinal_position;
   
  
 
+  <literal>enabled_roles</literal>
+
+  
+   The view enabled_roles identifies all groups
+   that the current user is a member of.  (A role is the same thing as
+   a group.)  The difference between this view and
+   applicable_roles is that in the future there may
+   be a mechanism to enable and disable groups during a session.  In
+   that case this view identifies those groups that are currently
+   enabled.
+  
+
+  
+   <literal>enabled_roles</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      role_name
+      sql_identifier
+      Name of a group
+     
+    
+   
+  
+
  
   <literal>key_column_usage</literal>
 
@@ -2066,6 +2160,334 @@ ORDER BY c.ordinal_position;
   
  
 
+  <literal>role_columns_grants</literal>
+
+  
+   The view role_column_grants identifies all
+   privileges granted on columns to a group that the current user is a
+   member of.  Further information can be found under
+   column_privileges.
+  
+
+  
+   <literal>role_column_grants</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      grantor
+      sql_identifier
+      Name of the user that granted the privilege
+     
+
+     
+      grantee
+      sql_identifier
+      Name of the group 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,
+       INSERTUPDATE, or
+       REFERENCES
+      
+     
+
+     
+      is_grantable
+      character_data
+      YES if the privilege is grantable, NO if not
+     
+    
+   
+  
+
+  <literal>role_routine_grants</literal>
+
+  
+   The view role_routine_grants identifies all
+   privileges granted on functions to a group that the current user is
+   a member of.  Further information can be found under
+   routine_privileges.
+  
+
+  
+   <literal>role_routine_grants</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      grantor
+      sql_identifier
+      Name of the user that granted the privilege
+     
+
+     
+      grantee
+      sql_identifier
+      Name of the group that the privilege was granted to
+     
+
+     
+      specific_catalog
+      sql_identifier
+      Name of the database containing the function (always the current database)
+     
+
+     
+      specific_schema
+      sql_identifier
+      Name of the schema containing the function
+     
+
+     
+      specific_name
+      sql_identifier
+      
+       The specific name of the function.  See 
+       linkend="infoschema-routines"> for more information.
+      
+     
+
+     
+      routine_catalog
+      sql_identifier
+      Name of the database containing the function (always the current database)
+     
+
+     
+      routine_schema
+      sql_identifier
+      Name of the schema containing the function
+     
+
+     
+      routine_name
+      sql_identifier
+      Name of the function (may be duplicated in case of overloading)
+     
+
+     
+      privilege_type
+      character_data
+      Always EXECUTE (the only privilege type for functions)
+     
+
+     
+      is_grantable
+      character_data
+      YES if the privilege is grantable, NO if not
+     
+    
+   
+  
+
+  <literal>role_table_grants</literal>
+
+  
+   The view role_table_grants identifies all
+   privileges granted on tables or views to a group that the current
+   user is a member of.  Further information can be found under
+   table_privileges.
+  
+
+  
+   <literal>role_table_grants</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      grantor
+      sql_identifier
+      Name of the user that granted the privilege
+     
+
+     
+      grantee
+      sql_identifier
+      Name of the group that the privilege was granted to
+     
+
+     
+      table_catalog
+      sql_identifier
+      Name of the database that contains the table (always the current database)
+     
+
+     
+      table_schema
+      sql_identifier
+      Name of the schema that contains the table
+     
+
+     
+      table_name
+      sql_identifier
+      Name of the table
+     
+
+     
+      privilege_type
+      character_data
+      
+       Type of the privilege: SELECT,
+       DELETEINSERT,
+       UPDATEREFERENCES,
+       RULE, or TRIGGER
+      
+     
+
+     
+      is_grantable
+      character_data
+      YES if the privilege is grantable, NO if not
+     
+
+     
+      with_hierarchy
+      character_data
+      Applies to a feature not available in PostgreSQL
+     
+    
+   
+  
+
+  <literal>role_usage_grants</literal>
+
+  
+   The view role_usage_grants is meant to identify
+   USAGE privileges granted on various kinds of
+   objects to a group that the current user is a member of.  In
+   PostgreSQL, this currently only applies to domains, and since
+   domains do not have real privileges in PostgreSQL, this view is
+   empty.  Futher information can be found under
+   usage_privileges.  In the future, this view may
+   contain more useful information.
+  
+
+  
+   <literal>role_usage_grants</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      grantor
+      sql_identifier
+      In the future, the name of the user that granted the privilege
+     
+
+     
+      grantee
+      sql_identifier
+      In the future, the name of the group that the privilege was granted to
+     
+
+     
+      object_catalog
+      sql_identifier
+      Name of the database containing the object (always the current database)
+     
+
+     
+      object_schema
+      sql_identifier
+      Name of the schema containing the object
+     
+
+     
+      object_name
+      sql_identifier
+      Name of the object
+     
+
+     
+      object_type
+      character_data
+      In the future, the type of the object
+     
+
+     
+      privilege_type
+      character_data
+      Always USAGE
+     
+
+     
+      is_grantable
+      character_data
+      YES if the privilege is grantable, NO if not
+     
+    
+   
+  
+
  
   <literal>routine_privileges</literal>
 
@@ -2073,7 +2495,8 @@ ORDER BY c.ordinal_position;
    The view routine_privileges identifies all
    privileges granted on functions to the current user or by the
    current user.  There is one row for each combination of function,
-   grantor, and grantee.
+   grantor, and grantee.  Privileges granted to groups are identified
+   in the view role_routine_grants.
   
 
   
@@ -2098,7 +2521,7 @@ ORDER BY c.ordinal_position;
      
       grantee
       sql_identifier
-      Name of the user that the privilege was granted to
+      Name of the user or group that the privilege was granted to
      
 
      
@@ -2154,6 +2577,14 @@ ORDER BY c.ordinal_position;
     
    
   
+
+  
+   Note that the column grantee makes no
+   distinction between users and groups.  If you have users and groups
+   with the same name, there is unfortunately no way to distinguish
+   them.  A future version of PostgreSQL will possibly prohibit having
+   users and groups with the same name.
+  
  
 
  
@@ -3147,9 +3578,10 @@ ORDER BY c.ordinal_position;
 
   
    The view table_privileges identifies all
-   privileges granted on tables to the current user or by the current
-   user.  There is one row for each combination of table, grantor, and
-   grantee.
+   privileges granted on tables or views to the current user or by the
+   current user.  There is one row for each combination of table,
+   grantor, and grantee.  Privileges granted to groups are identified
+   in the view role_table_grants.
   
 
   
@@ -3174,7 +3606,7 @@ ORDER BY c.ordinal_position;
      
       grantee
       sql_identifier
-      Name of the user that the privilege was granted to
+      Name of the user or group that the privilege was granted to
      
 
      
@@ -3201,8 +3633,8 @@ ORDER BY c.ordinal_position;
       
        Type of the privilege: SELECT,
        DELETEINSERT,
-       UPDATEREFERENCES, or
-       TRIGGER
+       UPDATEREFERENCES,
+       RULE, or TRIGGER
       
      
 
@@ -3220,6 +3652,14 @@ ORDER BY c.ordinal_position;
     
    
   
+
+  
+   Note that the column grantee makes no
+   distinction between users and groups.  If you have users and groups
+   with the same name, there is unfortunately no way to distinguish
+   them.  A future version of PostgreSQL will possibly prohibit having
+   users and groups with the same name.
+  
  
 
  
@@ -3459,6 +3899,85 @@ ORDER BY c.ordinal_position;
   
  
 
+  <literal>usage_privileges</literal>
+
+  
+   The view usage_privileges is meant to identify
+   USAGE privileges granted on various kinds of
+   objects to the current user or by the current user.  In PostgreSQL,
+   this currently only applies to domains, and since domains do not
+   have real privileges in PostgreSQL, this view shows implicit
+   USAGE privileges granted to
+   PUBLIC for all domains.  In the future, this
+   view may contain more useful information.
+  
+
+  
+   <literal>usage_privileges</literal> Columns
+
+   
+    
+     
+      Name
+      Data Type
+      Description
+     
+    
+
+    
+     
+      grantor
+      sql_identifier
+      Currently set to the name of the owner of the object
+     
+
+     
+      grantee
+      sql_identifier
+      Currently always PUBLIC
+     
+
+     
+      object_catalog
+      sql_identifier
+      Name of the database containing the object (always the current database)
+     
+
+     
+      object_schema
+      sql_identifier
+      Name of the schema containing the object
+     
+
+     
+      object_name
+      sql_identifier
+      Name of the object
+     
+
+     
+      object_type
+      character_data
+      Currently always DOMAIN
+     
+
+     
+      privilege_type
+      character_data
+      Always USAGE
+     
+
+     
+      is_grantable
+      character_data
+      Currently always NO
+     
+    
+   
+  
+
  
   <literal>view_column_usage</literal>
 
index cc73d5da01442e29ebe1c57e8ba452304184adc0..19acb61757d9d3b1d915f0ea55dad86598de91de 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright 2003, PostgreSQL Global Development Group
  *
- * $Id: information_schema.sql,v 1.11 2003/06/29 10:18:26 petere Exp $
+ * $Id: information_schema.sql,v 1.12 2003/06/29 15:14:41 petere Exp $
  */
 
 /*
@@ -75,6 +75,24 @@ CREATE DOMAIN time_stamp AS timestamp(2)
     DEFAULT current_timestamp(2);
 
 
+/*
+ * 20.9
+ * APPLICABLE_ROLES view
+ */
+
+CREATE VIEW applicable_roles AS
+    SELECT CAST(current_user AS sql_identifier) AS grantee,
+           CAST(g.groname AS sql_identifier) AS role_name,
+           CAST('NO' AS character_data) AS is_grantable
+
+    FROM pg_group g, pg_user u
+
+    WHERE u.usesysid = ANY (g.grolist)
+          AND u.usename = current_user;
+
+GRANT SELECT ON applicable_roles TO PUBLIC;
+
+
 /*
  * 20.13
  * CHECK_CONSTRAINTS view
@@ -137,7 +155,7 @@ GRANT SELECT ON column_domain_usage TO PUBLIC;
 
 CREATE VIEW column_privileges AS
     SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
-           CAST(u_grantee.usename AS sql_identifier) AS grantee,
+           CAST(grantee.name 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,
@@ -145,16 +163,21 @@ CREATE VIEW column_privileges AS
            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))
+                                   makeaclitem(grantee.usesysid, grantee.grosysid, 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)
+         (
+           SELECT usesysid, 0, usename FROM pg_user
+           UNION
+           SELECT 0, grosysid, groname FROM pg_group
+           UNION
+           SELECT 0, 0, 'PUBLIC'
+         ) AS grantee (usesysid, grosysid, name),
+         (SELECT 'SELECT' UNION SELECT 'INSERT' UNION SELECT 'UPDATE' UNION SELECT 'REFERENCES') AS pr (type)
 
     WHERE a.attrelid = c.oid
           AND c.relnamespace = nc.oid
@@ -162,10 +185,10 @@ CREATE VIEW column_privileges AS
           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))
+                          makeaclitem(grantee.usesysid, grantee.grosysid, u_grantor.usesysid, pr.type, false))
           AND (u_grantor.usename = current_user
-               OR u_grantee.usename = current_user
-               OR u_grantee.usename = 'PUBLIC');
+               OR grantee.name = current_user
+               OR grantee.name = 'PUBLIC');
 
 GRANT SELECT ON column_privileges TO PUBLIC;
 
@@ -355,10 +378,7 @@ CREATE VIEW columns AS
                OR has_table_privilege(c.oid, 'SELECT')
                OR has_table_privilege(c.oid, 'INSERT')
                OR has_table_privilege(c.oid, 'UPDATE')
-               OR has_table_privilege(c.oid, 'DELETE')
-               OR has_table_privilege(c.oid, 'RULE')
-               OR has_table_privilege(c.oid, 'RERERENCES')
-               OR has_table_privilege(c.oid, 'TRIGGER') );
+               OR has_table_privilege(c.oid, 'RERERENCES') );
 
 GRANT SELECT ON columns TO PUBLIC;
 
@@ -609,6 +629,20 @@ GRANT SELECT ON domains TO PUBLIC;
 -- 20.27 ELEMENT_TYPES view appears later.
 
 
+/*
+ * 20.28
+ * ENABLED_ROLES view
+ */
+
+CREATE VIEW enabled_roles AS
+    SELECT CAST(g.groname AS sql_identifier) AS role_name
+    FROM pg_group g, pg_user u
+    WHERE u.usesysid = ANY (g.grolist)
+          AND u.usename = current_user;
+
+GRANT SELECT ON enabled_roles TO PUBLIC;
+
+
 /*
  * 20.30
  * KEY_COLUMN_USAGE view
@@ -761,6 +795,132 @@ CREATE VIEW referential_constraints AS
 GRANT SELECT ON referential_constraints TO PUBLIC;
 
 
+/*
+ * 20.36
+ * ROLE_COLUMN_GRANTS view
+ */
+
+CREATE VIEW role_column_grants AS
+    SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
+           CAST(g_grantee.groname 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(0, g_grantee.grosysid, 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,
+         pg_group g_grantee,
+         (SELECT 'SELECT' UNION SELECT 'INSERT' UNION SELECT 'UPDATE' UNION SELECT 'REFERENCES') 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(0, g_grantee.grosysid, u_grantor.usesysid, pr.type, false))
+          AND g_grantee.groname IN (SELECT role_name FROM enabled_roles);
+
+GRANT SELECT ON role_column_grants TO PUBLIC;
+
+
+/*
+ * 20.37
+ * ROLE_ROUTINE_GRANTS view
+ */
+
+CREATE VIEW role_routine_grants AS
+    SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
+           CAST(g_grantee.groname AS sql_identifier) AS grantee,
+           CAST(current_database() AS sql_identifier) AS specific_catalog,
+           CAST(n.nspname AS sql_identifier) AS specific_schema,
+           CAST(p.proname || '_' || CAST(p.oid AS text) AS sql_identifier) AS specific_name,
+           CAST(current_database() AS sql_identifier) AS routine_catalog,
+           CAST(n.nspname AS sql_identifier) AS routine_schema,
+           CAST(p.proname AS sql_identifier) AS routine_name,
+           CAST('EXECUTE' AS character_data) AS privilege_type,
+           CAST(
+             CASE WHEN aclcontains(p.proacl,
+                                   makeaclitem(0, g_grantee.grosysid, u_grantor.usesysid, 'EXECUTE', true))
+                  THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
+
+    FROM pg_proc p,
+         pg_namespace n,
+         pg_user u_grantor,
+         pg_group g_grantee
+
+    WHERE p.pronamespace = n.oid
+          AND aclcontains(p.proacl,
+                          makeaclitem(0, g_grantee.grosysid, u_grantor.usesysid, 'EXECUTE', false))
+          AND g_grantee.groname IN (SELECT role_name FROM enabled_roles);
+
+GRANT SELECT ON role_routine_grants TO PUBLIC;
+
+
+/*
+ * 20.38
+ * ROLE_TABLE_GRANTS view
+ */
+
+CREATE VIEW role_table_grants AS
+    SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
+           CAST(g_grantee.groname 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(pr.type AS character_data) AS privilege_type,
+           CAST(
+             CASE WHEN aclcontains(c.relacl,
+                                   makeaclitem(0, g_grantee.grosysid, u_grantor.usesysid, pr.type, true))
+                  THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable,
+           CAST('NO' AS character_data) AS with_hierarchy
+
+    FROM pg_class c,
+         pg_namespace nc,
+         pg_user u_grantor,
+         pg_group g_grantee,
+         (SELECT 'SELECT' UNION SELECT 'DELETE' UNION SELECT 'INSERT' UNION SELECT 'UPDATE'
+          UNION SELECT 'REFERENCES' UNION SELECT 'RULE' UNION SELECT 'TRIGGER') AS pr (type)
+
+    WHERE c.relnamespace = nc.oid
+          AND c.relkind IN ('r', 'v')
+          AND aclcontains(c.relacl,
+                          makeaclitem(0, g_grantee.grosysid, u_grantor.usesysid, pr.type, false))
+          AND g_grantee.groname IN (SELECT role_name FROM enabled_roles);
+
+GRANT SELECT ON role_table_grants TO PUBLIC;
+
+
+/*
+ * 20.40
+ * ROLE_USAGE_GRANTS view
+ */
+
+-- See USAGE_PRIVILEGES.
+
+CREATE VIEW role_usage_grants AS
+    SELECT CAST(null AS sql_identifier) AS grantor,
+           CAST(null AS sql_identifier) AS grantee,
+           CAST(current_database() AS sql_identifier) AS object_catalog,
+           CAST(null AS sql_identifier) AS object_schema,
+           CAST(null AS sql_identifier) AS object_name,
+           CAST(null AS character_data) AS object_type,
+           CAST('USAGE' AS character_data) AS privilege_type,
+           CAST(null AS character_data) AS is_grantable
+
+    WHERE false;
+
+GRANT SELECT ON role_usage_grants TO PUBLIC;
+
+
 /*
  * 20.43
  * ROUTINE_PRIVILEGES view
@@ -768,7 +928,7 @@ GRANT SELECT ON referential_constraints TO PUBLIC;
 
 CREATE VIEW routine_privileges AS
     SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
-           CAST(u_grantee.usename AS sql_identifier) AS grantee,
+           CAST(grantee.name AS sql_identifier) AS grantee,
            CAST(current_database() AS sql_identifier) AS specific_catalog,
            CAST(n.nspname AS sql_identifier) AS specific_schema,
            CAST(p.proname || '_' || CAST(p.oid AS text) AS sql_identifier) AS specific_name,
@@ -778,20 +938,26 @@ CREATE VIEW routine_privileges AS
            CAST('EXECUTE' AS character_data) AS privilege_type,
            CAST(
              CASE WHEN aclcontains(p.proacl,
-                                   makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, 'EXECUTE', true))
+                                   makeaclitem(grantee.usesysid, grantee.grosysid, u_grantor.usesysid, 'EXECUTE', true))
                   THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
 
     FROM pg_proc p,
          pg_namespace n,
          pg_user u_grantor,
-         (SELECT usesysid, usename FROM pg_user UNION SELECT 0, 'PUBLIC') AS u_grantee
+         (
+           SELECT usesysid, 0, usename FROM pg_user
+           UNION
+           SELECT 0, grosysid, groname FROM pg_group
+           UNION
+           SELECT 0, 0, 'PUBLIC'
+         ) AS grantee (usesysid, grosysid, name)
 
     WHERE p.pronamespace = n.oid
           AND aclcontains(p.proacl,
-                          makeaclitem(u_grantee.usesysid, 0, u_grantor.usesysid, 'EXECUTE', false))
+                          makeaclitem(grantee.usesysid, grantee.grosysid, u_grantor.usesysid, 'EXECUTE', false))
           AND (u_grantor.usename = current_user
-               OR u_grantee.usename = current_user
-               OR u_grantee.usename = 'PUBLIC');
+               OR grantee.name = current_user
+               OR grantee.name = 'PUBLIC');
 
 GRANT SELECT ON routine_privileges TO PUBLIC;
 
@@ -1110,31 +1276,37 @@ GRANT SELECT ON table_constraints TO PUBLIC;
 
 CREATE VIEW table_privileges AS
     SELECT CAST(u_grantor.usename AS sql_identifier) AS grantor,
-           CAST(u_grantee.usename AS sql_identifier) AS grantee,
+           CAST(grantee.name 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(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))
+                                   makeaclitem(grantee.usesysid, grantee.grosysid, u_grantor.usesysid, pr.type, true))
                   THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable,
            CAST('NO' AS character_data) AS with_hierarchy
 
     FROM pg_class c,
          pg_namespace nc,
          pg_user u_grantor,
-         (SELECT usesysid, usename FROM pg_user UNION SELECT 0, 'PUBLIC') AS u_grantee,
+         (
+           SELECT usesysid, 0, usename FROM pg_user
+           UNION
+           SELECT 0, grosysid, groname FROM pg_group
+           UNION
+           SELECT 0, 0, 'PUBLIC'
+         ) AS grantee (usesysid, grosysid, name),
          (SELECT 'SELECT' UNION SELECT 'DELETE' UNION SELECT 'INSERT' UNION SELECT 'UPDATE'
-          UNION SELECT 'REFERENCES' UNION SELECT 'TRIGGER') AS pr (type)
+          UNION SELECT 'REFERENCES' UNION SELECT 'RULE' 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))
+                          makeaclitem(grantee.usesysid, grantee.grosysid, u_grantor.usesysid, pr.type, false))
           AND (u_grantor.usename = current_user
-               OR u_grantee.usename = current_user
-               OR u_grantee.usename = 'PUBLIC');
+               OR grantee.name = current_user
+               OR grantee.name = 'PUBLIC');
 
 GRANT SELECT ON table_privileges TO PUBLIC;