summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2009-12-05 21:43:36 +0000
committerPeter Eisentraut <peter_e@gmx.net>2009-12-05 21:43:36 +0000
commit36f887c41c294d0035d84dfac75b4cc68a514950 (patch)
tree0481aff6c13784e06286065f3b0919aeee6a9453
parent636bac6e4617caa60dbbd5a2e3f4cf7afa88281a (diff)
downloadpostgresql-36f887c41c294d0035d84dfac75b4cc68a514950.tar.gz
Speed up information schema privilege views
Instead of expensive cross joins to resolve the ACL, add table-returning function aclexplode() that expands the ACL into a useful form, and join against that. Also, implement the role_*_grants views as a thin layer over the respective *_privileges views instead of essentially repeating the same code twice. fixes bug #4596 by Joachim Wieland, with cleanup by me
-rw-r--r--src/backend/catalog/information_schema.sql382
-rw-r--r--src/backend/utils/adt/acl.c140
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/catalog/pg_proc.h4
-rw-r--r--src/include/utils/acl.h3
5 files changed, 301 insertions, 232 deletions
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index 36f5b62b4e..e973b0abc6 100644
--- a/src/backend/catalog/information_schema.sql
+++ b/src/backend/catalog/information_schema.sql
@@ -4,7 +4,7 @@
*
* Copyright (c) 2003-2009, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.58 2009/07/28 02:56:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.59 2009/12/05 21:43:35 petere Exp $
*/
/*
@@ -483,42 +483,63 @@ CREATE VIEW column_privileges AS
CAST(grantee.rolname 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(x.relname AS sql_identifier) AS table_name,
+ CAST(x.attname AS sql_identifier) AS column_name,
+ CAST(x.prtype AS character_data) AS privilege_type,
CAST(
CASE WHEN
-- object owner always has grant options
- pg_has_role(grantee.oid, c.relowner, 'USAGE')
- OR aclcontains(c.relacl,
- makeaclitem(grantee.oid, u_grantor.oid, pr.type, true))
- OR aclcontains(a.attacl,
- makeaclitem(grantee.oid, u_grantor.oid, pr.type, true))
+ pg_has_role(x.grantee, x.relowner, 'USAGE')
+ OR x.grantable
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
- FROM pg_attribute a,
- pg_class c,
+ FROM (
+ SELECT pr_c.grantor,
+ pr_c.grantee,
+ attname,
+ relname,
+ relnamespace,
+ pr_c.prtype,
+ pr_c.grantable,
+ pr_c.relowner
+ FROM (SELECT oid, relname, relnamespace, relowner, (aclexplode(relacl)).*
+ FROM pg_class
+ WHERE relkind IN ('r', 'v')
+ ) pr_c (oid, relname, relnamespace, relowner, grantor, grantee, prtype, grantable),
+ pg_attribute a
+ WHERE a.attrelid = pr_c.oid
+ AND a.attnum > 0
+ AND NOT a.attisdropped
+ UNION
+ SELECT pr_a.grantor,
+ pr_a.grantee,
+ attname,
+ relname,
+ relnamespace,
+ pr_a.prtype,
+ pr_a.grantable,
+ c.relowner
+ FROM (SELECT attrelid, attname, (aclexplode(attacl)).*
+ FROM pg_attribute
+ WHERE attnum > 0
+ AND NOT attisdropped
+ ) pr_a (attrelid, attname, grantor, grantee, prtype, grantable),
+ pg_class c
+ WHERE pr_a.attrelid = c.oid
+ AND relkind IN ('r','v')
+ ) x,
pg_namespace nc,
pg_authid u_grantor,
(
SELECT oid, rolname FROM pg_authid
UNION ALL
SELECT 0::oid, 'PUBLIC'
- ) AS grantee (oid, rolname),
- (VALUES ('SELECT'),
- ('INSERT'),
- ('UPDATE'),
- ('REFERENCES')) AS pr (type)
+ ) AS grantee (oid, rolname)
- 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(grantee.oid, u_grantor.oid, pr.type, false))
- OR aclcontains(a.attacl,
- makeaclitem(grantee.oid, u_grantor.oid, pr.type, false)))
+ WHERE x.relnamespace = nc.oid
+ AND x.grantee = grantee.oid
+ AND x.grantor = u_grantor.oid
+ AND x.prtype IN ('INSERT', 'SELECT', 'UPDATE', 'REFERENCES')
AND (pg_has_role(u_grantor.oid, 'USAGE')
OR pg_has_role(grantee.oid, 'USAGE')
OR grantee.rolname = 'PUBLIC');
@@ -1124,126 +1145,25 @@ GRANT SELECT ON referential_constraints TO PUBLIC;
*/
CREATE VIEW role_column_grants AS
- SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
- CAST(g_grantee.rolname 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
- -- object owner always has grant options
- pg_has_role(g_grantee.oid, c.relowner, 'USAGE')
- OR aclcontains(c.relacl,
- makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, true))
- OR aclcontains(a.attacl,
- makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, true))
- THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
-
- FROM pg_attribute a,
- pg_class c,
- pg_namespace nc,
- pg_authid u_grantor,
- pg_authid g_grantee,
- (VALUES ('SELECT'),
- ('INSERT'),
- ('UPDATE'),
- ('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(g_grantee.oid, u_grantor.oid, pr.type, false))
- OR aclcontains(a.attacl,
- makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, false)))
- AND (u_grantor.rolname IN (SELECT role_name FROM enabled_roles)
- OR g_grantee.rolname IN (SELECT role_name FROM enabled_roles));
+ SELECT grantor,
+ grantee,
+ table_catalog,
+ table_schema,
+ table_name,
+ column_name,
+ privilege_type,
+ is_grantable
+ FROM column_privileges
+ WHERE grantor IN (SELECT role_name FROM enabled_roles)
+ OR grantee IN (SELECT role_name FROM enabled_roles);
GRANT SELECT ON role_column_grants TO PUBLIC;
-/*
- * 5.39
- * ROLE_ROUTINE_GRANTS view
- */
-
-CREATE VIEW role_routine_grants AS
- SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
- CAST(g_grantee.rolname 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
- -- object owner always has grant options
- pg_has_role(g_grantee.oid, p.proowner, 'USAGE')
- OR aclcontains(p.proacl,
- makeaclitem(g_grantee.oid, u_grantor.oid, 'EXECUTE', true))
- THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
-
- FROM pg_proc p,
- pg_namespace n,
- pg_authid u_grantor,
- pg_authid g_grantee
+-- 5.39 ROLE_ROUTINE_GRANTS view is based on 5.45 ROUTINE_PRIVILEGES and is defined there instead.
- WHERE p.pronamespace = n.oid
- AND aclcontains(p.proacl,
- makeaclitem(g_grantee.oid, u_grantor.oid, 'EXECUTE', false))
- AND (u_grantor.rolname IN (SELECT role_name FROM enabled_roles)
- OR g_grantee.rolname IN (SELECT role_name FROM enabled_roles));
-GRANT SELECT ON role_routine_grants TO PUBLIC;
-
-
-/*
- * 5.40
- * ROLE_TABLE_GRANTS view
- */
-
-CREATE VIEW role_table_grants AS
- SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
- CAST(g_grantee.rolname 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
- -- object owner always has grant options
- pg_has_role(g_grantee.oid, c.relowner, 'USAGE')
- OR aclcontains(c.relacl,
- makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, true))
- THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable,
- CAST('NO' AS yes_or_no) AS with_hierarchy
-
- FROM pg_class c,
- pg_namespace nc,
- pg_authid u_grantor,
- pg_authid g_grantee,
- (VALUES ('SELECT'),
- ('INSERT'),
- ('UPDATE'),
- ('DELETE'),
- ('TRUNCATE'),
- ('REFERENCES'),
- ('TRIGGER')) AS pr (type)
-
- WHERE c.relnamespace = nc.oid
- AND c.relkind IN ('r', 'v')
- AND aclcontains(c.relacl,
- makeaclitem(g_grantee.oid, u_grantor.oid, pr.type, false))
- AND (u_grantor.rolname IN (SELECT role_name FROM enabled_roles)
- OR g_grantee.rolname IN (SELECT role_name FROM enabled_roles));
-
-GRANT SELECT ON role_table_grants TO PUBLIC;
+-- 5.40 ROLE_TABLE_GRANTS view is based on 5.60 TABLE_PRIVILEGES and is defined there instead.
/*
@@ -1254,66 +1174,8 @@ GRANT SELECT ON role_table_grants TO PUBLIC;
-- feature not supported
-/*
- * 5.42
- * ROLE_USAGE_GRANTS view
- */
-
-CREATE VIEW role_usage_grants AS
-
- /* foreign-data wrappers */
- SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
- CAST(g_grantee.rolname AS sql_identifier) AS grantee,
- CAST(current_database() AS sql_identifier) AS object_catalog,
- CAST('' AS sql_identifier) AS object_schema,
- CAST(fdw.fdwname AS sql_identifier) AS object_name,
- CAST('FOREIGN DATA WRAPPER' AS character_data) AS object_type,
- CAST('USAGE' AS character_data) AS privilege_type,
- CAST(
- CASE WHEN
- -- object owner always has grant options
- pg_has_role(g_grantee.oid, fdw.fdwowner, 'USAGE')
- OR aclcontains(fdw.fdwacl,
- makeaclitem(g_grantee.oid, u_grantor.oid, 'USAGE', true))
- THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
-
- FROM pg_foreign_data_wrapper fdw,
- pg_authid u_grantor,
- pg_authid g_grantee
-
- WHERE aclcontains(fdw.fdwacl,
- makeaclitem(g_grantee.oid, u_grantor.oid, 'USAGE', false))
- AND (u_grantor.rolname IN (SELECT role_name FROM enabled_roles)
- OR g_grantee.rolname IN (SELECT role_name FROM enabled_roles))
- UNION ALL
-
- /* foreign server */
- SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
- CAST(g_grantee.rolname AS sql_identifier) AS grantee,
- CAST(current_database() AS sql_identifier) AS object_catalog,
- CAST('' AS sql_identifier) AS object_schema,
- CAST(srv.srvname AS sql_identifier) AS object_name,
- CAST('FOREIGN SERVER' AS character_data) AS object_type,
- CAST('USAGE' AS character_data) AS privilege_type,
- CAST(
- CASE WHEN
- -- object owner always has grant options
- pg_has_role(g_grantee.oid, srv.srvowner, 'USAGE')
- OR aclcontains(srv.srvacl,
- makeaclitem(g_grantee.oid, u_grantor.oid, 'USAGE', true))
- THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
-
- FROM pg_foreign_server srv,
- pg_authid u_grantor,
- pg_authid g_grantee
-
- WHERE aclcontains(srv.srvacl,
- makeaclitem(g_grantee.oid, u_grantor.oid, 'USAGE', false))
- AND (u_grantor.rolname IN (SELECT role_name FROM enabled_roles)
- OR g_grantee.rolname IN (SELECT role_name FROM enabled_roles));
-
-GRANT SELECT ON role_usage_grants TO PUBLIC;
+-- 5.42 ROLE_USAGE_GRANTS view is based on 5.71 USAGE_PRIVILEGES and is defined there instead.
/*
@@ -1351,11 +1213,12 @@ CREATE VIEW routine_privileges AS
CASE WHEN
-- object owner always has grant options
pg_has_role(grantee.oid, p.proowner, 'USAGE')
- OR aclcontains(p.proacl,
- makeaclitem(grantee.oid, u_grantor.oid, 'EXECUTE', true))
+ OR p.grantable
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
- FROM pg_proc p,
+ FROM (
+ SELECT oid, proname, proowner, pronamespace, (aclexplode(proacl)).* FROM pg_proc
+ ) p (oid, proname, proowner, pronamespace, grantor, grantee, prtype, grantable),
pg_namespace n,
pg_authid u_grantor,
(
@@ -1365,8 +1228,9 @@ CREATE VIEW routine_privileges AS
) AS grantee (oid, rolname)
WHERE p.pronamespace = n.oid
- AND aclcontains(p.proacl,
- makeaclitem(grantee.oid, u_grantor.oid, 'EXECUTE', false))
+ AND grantee.oid = p.grantee
+ AND u_grantor.oid = p.grantor
+ AND p.prtype IN ('EXECUTE')
AND (pg_has_role(u_grantor.oid, 'USAGE')
OR pg_has_role(grantee.oid, 'USAGE')
OR grantee.rolname = 'PUBLIC');
@@ -1375,6 +1239,29 @@ GRANT SELECT ON routine_privileges TO PUBLIC;
/*
+ * 5.39
+ * ROLE_ROUTINE_GRANTS view
+ */
+
+CREATE VIEW role_routine_grants AS
+ SELECT grantor,
+ grantee,
+ specific_catalog,
+ specific_schema,
+ specific_name,
+ routine_catalog,
+ routine_schema,
+ routine_name,
+ privilege_type,
+ is_grantable
+ FROM routine_privileges
+ WHERE grantor IN (SELECT role_name FROM enabled_roles)
+ OR grantee IN (SELECT role_name FROM enabled_roles);
+
+GRANT SELECT ON role_routine_grants TO PUBLIC;
+
+
+/*
* 5.46
* ROUTINE_ROUTINE_USAGE view
*/
@@ -1838,36 +1725,31 @@ CREATE VIEW table_privileges AS
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(c.prtype AS character_data) AS privilege_type,
CAST(
CASE WHEN
-- object owner always has grant options
pg_has_role(grantee.oid, c.relowner, 'USAGE')
- OR aclcontains(c.relacl,
- makeaclitem(grantee.oid, u_grantor.oid, pr.type, true))
+ OR c.grantable
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable,
CAST('NO' AS yes_or_no) AS with_hierarchy
- FROM pg_class c,
+ FROM (
+ SELECT oid, relname, relnamespace, relkind, relowner, (aclexplode(relacl)).* FROM pg_class
+ ) AS c (oid, relname, relnamespace, relkind, relowner, grantor, grantee, prtype, grantable),
pg_namespace nc,
pg_authid u_grantor,
(
SELECT oid, rolname FROM pg_authid
UNION ALL
SELECT 0::oid, 'PUBLIC'
- ) AS grantee (oid, rolname),
- (VALUES ('SELECT'),
- ('INSERT'),
- ('UPDATE'),
- ('DELETE'),
- ('TRUNCATE'),
- ('REFERENCES'),
- ('TRIGGER')) AS pr (type)
+ ) AS grantee (oid, rolname)
WHERE c.relnamespace = nc.oid
AND c.relkind IN ('r', 'v')
- AND aclcontains(c.relacl,
- makeaclitem(grantee.oid, u_grantor.oid, pr.type, false))
+ AND c.grantee = grantee.oid
+ AND c.grantor = u_grantor.oid
+ AND c.prtype IN ('INSERT', 'SELECT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER')
AND (pg_has_role(u_grantor.oid, 'USAGE')
OR pg_has_role(grantee.oid, 'USAGE')
OR grantee.rolname = 'PUBLIC');
@@ -1876,6 +1758,27 @@ GRANT SELECT ON table_privileges TO PUBLIC;
/*
+ * 5.40
+ * ROLE_TABLE_GRANTS view
+ */
+
+CREATE VIEW role_table_grants AS
+ SELECT grantor,
+ grantee,
+ table_catalog,
+ table_schema,
+ table_name,
+ privilege_type,
+ is_grantable,
+ with_hierarchy
+ FROM table_privileges
+ WHERE grantor IN (SELECT role_name FROM enabled_roles)
+ OR grantee IN (SELECT role_name FROM enabled_roles);
+
+GRANT SELECT ON role_table_grants TO PUBLIC;
+
+
+/*
* 5.61
* TABLES view
*/
@@ -2088,11 +1991,12 @@ CREATE VIEW usage_privileges AS
CASE WHEN
-- object owner always has grant options
pg_has_role(grantee.oid, fdw.fdwowner, 'USAGE')
- OR aclcontains(fdw.fdwacl,
- makeaclitem(grantee.oid, u_grantor.oid, 'USAGE', true))
+ OR fdw.grantable
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
- FROM pg_foreign_data_wrapper fdw,
+ FROM (
+ SELECT fdwname, fdwowner, (aclexplode(fdwacl)).* FROM pg_foreign_data_wrapper
+ ) AS fdw (fdwname, fdwowner, grantor, grantee, prtype, grantable),
pg_authid u_grantor,
(
SELECT oid, rolname FROM pg_authid
@@ -2100,8 +2004,9 @@ CREATE VIEW usage_privileges AS
SELECT 0::oid, 'PUBLIC'
) AS grantee (oid, rolname)
- WHERE aclcontains(fdw.fdwacl,
- makeaclitem(grantee.oid, u_grantor.oid, 'USAGE', false))
+ WHERE u_grantor.oid = fdw.grantor
+ AND grantee.oid = fdw.grantee
+ AND fdw.prtype IN ('USAGE')
AND (pg_has_role(u_grantor.oid, 'USAGE')
OR pg_has_role(grantee.oid, 'USAGE')
OR grantee.rolname = 'PUBLIC')
@@ -2120,11 +2025,12 @@ CREATE VIEW usage_privileges AS
CASE WHEN
-- object owner always has grant options
pg_has_role(grantee.oid, srv.srvowner, 'USAGE')
- OR aclcontains(srv.srvacl,
- makeaclitem(grantee.oid, u_grantor.oid, 'USAGE', true))
+ OR srv.grantable
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
- FROM pg_foreign_server srv,
+ FROM (
+ SELECT srvname, srvowner, (aclexplode(srvacl)).* FROM pg_foreign_server
+ ) AS srv (srvname, srvowner, grantor, grantee, prtype, grantable),
pg_authid u_grantor,
(
SELECT oid, rolname FROM pg_authid
@@ -2132,8 +2038,9 @@ CREATE VIEW usage_privileges AS
SELECT 0::oid, 'PUBLIC'
) AS grantee (oid, rolname)
- WHERE aclcontains(srv.srvacl,
- makeaclitem(grantee.oid, u_grantor.oid, 'USAGE', false))
+ WHERE u_grantor.oid = srv.grantor
+ AND grantee.oid = srv.grantee
+ AND srv.prtype IN ('USAGE')
AND (pg_has_role(u_grantor.oid, 'USAGE')
OR pg_has_role(grantee.oid, 'USAGE')
OR grantee.rolname = 'PUBLIC');
@@ -2142,6 +2049,27 @@ GRANT SELECT ON usage_privileges TO PUBLIC;
/*
+ * 5.42
+ * ROLE_USAGE_GRANTS view
+ */
+
+CREATE VIEW role_usage_grants AS
+ SELECT grantor,
+ grantee,
+ object_catalog,
+ object_schema,
+ object_name,
+ object_type,
+ privilege_type,
+ is_grantable
+ FROM usage_privileges
+ WHERE grantor IN (SELECT role_name FROM enabled_roles)
+ OR grantee IN (SELECT role_name FROM enabled_roles);
+
+GRANT SELECT ON role_usage_grants TO PUBLIC;
+
+
+/*
* 5.72
* USER_DEFINED_TYPES view
*/
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 1264dfddb3..142e06cf45 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.150 2009/10/05 19:24:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.151 2009/12/05 21:43:35 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,6 +24,7 @@
#include "commands/dbcommands.h"
#include "commands/tablespace.h"
#include "foreign/foreign.h"
+#include "funcapi.h"
#include "miscadmin.h"
#include "utils/acl.h"
#include "utils/builtins.h"
@@ -1622,6 +1623,143 @@ convert_any_priv_string(text *priv_type_text,
}
+static const char *
+convert_aclright_to_string(int aclright)
+{
+ switch (aclright)
+ {
+ case ACL_INSERT:
+ return "INSERT";
+ case ACL_SELECT:
+ return "SELECT";
+ case ACL_UPDATE:
+ return "UPDATE";
+ case ACL_DELETE:
+ return "DELETE";
+ case ACL_TRUNCATE:
+ return "TRUNCATE";
+ case ACL_REFERENCES:
+ return "REFERENCES";
+ case ACL_TRIGGER:
+ return "TRIGGER";
+ case ACL_EXECUTE:
+ return "EXECUTE";
+ case ACL_USAGE:
+ return "USAGE";
+ case ACL_CREATE:
+ return "CREATE";
+ case ACL_CREATE_TEMP:
+ return "TEMPORARY";
+ case ACL_CONNECT:
+ return "CONNECT";
+ default:
+ elog(ERROR, "unrecognized aclright: %d", aclright);
+ return NULL;
+ }
+}
+
+
+/*----------
+ * Convert an aclitem[] to a table.
+ *
+ * Example:
+ *
+ * aclexplode('{=r/joe,foo=a*w/joe}'::aclitem[])
+ *
+ * returns the table
+ *
+ * {{ OID(joe), 0::OID, 'SELECT', false },
+ * { OID(joe), OID(foo), 'INSERT', true },
+ * { OID(joe), OID(foo), 'UPDATE', false }}
+ *----------
+ */
+Datum
+aclexplode(PG_FUNCTION_ARGS)
+{
+ FuncCallContext *funcctx;
+ int *idx;
+ Acl *acl = PG_GETARG_ACL_P(0);
+ AclItem *aidat;
+
+ if (SRF_IS_FIRSTCALL())
+ {
+ TupleDesc tupdesc;
+ MemoryContext oldcontext;
+
+ check_acl(acl);
+
+ funcctx = SRF_FIRSTCALL_INIT();
+ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+ /*
+ * build tupdesc for result tuples (matches out parameters in
+ * pg_proc entry)
+ */
+ tupdesc = CreateTemplateTupleDesc(4, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "grantor",
+ OIDOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "grantee",
+ OIDOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "privilege_type",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_grantable",
+ BOOLOID, -1, 0);
+
+ funcctx->tuple_desc = BlessTupleDesc(tupdesc);
+
+ /* allocate memory for user context */
+ idx = (int *) palloc(sizeof(int[2]));
+ idx[0] = 0; /* ACL array item index */
+ idx[1] = -1; /* privilege type counter */
+ funcctx->user_fctx = (void *) idx;
+
+ MemoryContextSwitchTo(oldcontext);
+ }
+
+ funcctx = SRF_PERCALL_SETUP();
+ idx = (int *) funcctx->user_fctx;
+
+ aidat = ACL_DAT(acl);
+ while (1)
+ {
+ idx[1]++;
+ if (idx[1] == N_ACL_RIGHTS)
+ {
+ idx[1] = 0;
+ idx[0]++;
+ if (idx[0] == ACL_NUM(acl))
+ /* done */
+ break;
+ }
+
+ Assert(idx[0] < ACL_NUM(acl));
+ Assert(idx[1] < N_ACL_RIGHTS);
+
+ if (ACLITEM_GET_PRIVS(aidat[idx[0]]) & (1 << idx[1]))
+ {
+ Datum result;
+ Datum values[4];
+ bool nulls[4];
+ HeapTuple tuple;
+
+ values[0] = ObjectIdGetDatum(aidat[idx[0]].ai_grantor);
+ values[1] = ObjectIdGetDatum(aidat[idx[0]].ai_grantee);
+ values[2] = CStringGetTextDatum(convert_aclright_to_string(1 << idx[1]));
+ values[3] = BoolGetDatum(ACLITEM_GET_GOPTIONS(aidat[idx[0]]) & (1 << idx[1]));
+
+ MemSet(nulls, 0, sizeof(nulls));
+
+ tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
+ result = HeapTupleGetDatum(tuple);
+
+ SRF_RETURN_NEXT(funcctx, result);
+ }
+ }
+
+ SRF_RETURN_DONE(funcctx);
+}
+
+
/*
* has_table_privilege variants
* These are all named "has_table_privilege" at the SQL level.
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index ad9c47a0b0..83ba592aa3 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.554 2009/11/29 18:14:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.555 2009/12/05 21:43:35 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200911291
+#define CATALOG_VERSION_NO 200912051
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index d6191e61e4..ee0a22eace 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.554 2009/11/29 18:14:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.555 2009/12/05 21:43:35 petere Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@@ -1314,6 +1314,8 @@ DATA(insert OID = 1062 ( aclitemeq PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16
DESCR("equality operator for ACL items");
DATA(insert OID = 1365 ( makeaclitem PGNSP PGUID 12 1 0 0 f f f t f i 4 0 1033 "26 26 25 16" _null_ _null_ _null_ _null_ makeaclitem _null_ _null_ _null_ ));
DESCR("make ACL item");
+DATA(insert OID = 1248 ( aclexplode PGNSP PGUID 12 1 10 0 f f f t t s 1 0 2249 "1034" "{1034,26,26,25,16}" "{i,o,o,o,o}" "{acl,grantor,grantee,privilege_type,is_grantable}" _null_ aclexplode _null_ _null_ _null_ ));
+DESCR("convert ACL item array to table, for use by information schema");
DATA(insert OID = 1044 ( bpcharin PGNSP PGUID 12 1 0 0 f f f t f i 3 0 1042 "2275 26 23" _null_ _null_ _null_ _null_ bpcharin _null_ _null_ _null_ ));
DESCR("I/O");
DATA(insert OID = 1045 ( bpcharout PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2275 "1042" _null_ _null_ _null_ _null_ bpcharout _null_ _null_ _null_ ));
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 977b00de79..039d27b59c 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.109 2009/10/05 19:24:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.110 2009/12/05 21:43:36 petere Exp $
*
* NOTES
* An ACL array is simply an array of AclItems, representing the union
@@ -238,6 +238,7 @@ extern Datum aclcontains(PG_FUNCTION_ARGS);
extern Datum makeaclitem(PG_FUNCTION_ARGS);
extern Datum aclitem_eq(PG_FUNCTION_ARGS);
extern Datum hash_aclitem(PG_FUNCTION_ARGS);
+extern Datum aclexplode(PG_FUNCTION_ARGS);
/*
* prototypes for functions in aclchk.c