information schema/aclexplode doesn't know about default privileges
Try this:
create function foo(int) returns int as $$ select $1 $$ language sql;
select * from information_schema.routine_privileges;
This ought to show EXECUTE privilege on the new function, but it
doesn't, because proacl is null, and nothing in the information schema
handles that specially.
I've pondered some ways to fix that. One would be to add a variant of
aclexplode() that takes a parameter telling which catalog the acl datum
came from, and aclexplode() could then substitute the data received
acldefault() for null values. The other way would be to handle this
entirely in the information schema SQL (either using some coalesce calls
or perhaps a UNION). But that would mean duplicating the knowledge of
acldefault() in a second remote place. So I'm thinking that handling it
in aclexplode() would be better.
Comments?
Peter Eisentraut <peter_e@gmx.net> writes:
This ought to show EXECUTE privilege on the new function, but it
doesn't, because proacl is null, and nothing in the information schema
handles that specially.
I've pondered some ways to fix that. One would be to add a variant of
aclexplode() that takes a parameter telling which catalog the acl datum
came from, and aclexplode() could then substitute the data received
acldefault() for null values. The other way would be to handle this
entirely in the information schema SQL (either using some coalesce calls
or perhaps a UNION). But that would mean duplicating the knowledge of
acldefault() in a second remote place. So I'm thinking that handling it
in aclexplode() would be better.
+1. It would be a really bad idea for the acldefault() logic to be
duplicated someplace else, especially in SQL code where grepping for the
relevant macros wouldn't even find it.
regards, tom lane
On sön, 2011-11-27 at 17:29 -0500, Tom Lane wrote:
Peter Eisentraut <peter_e@gmx.net> writes:
This ought to show EXECUTE privilege on the new function, but it
doesn't, because proacl is null, and nothing in the information schema
handles that specially.I've pondered some ways to fix that. One would be to add a variant of
aclexplode() that takes a parameter telling which catalog the acl datum
came from, and aclexplode() could then substitute the data received
acldefault() for null values. The other way would be to handle this
entirely in the information schema SQL (either using some coalesce calls
or perhaps a UNION). But that would mean duplicating the knowledge of
acldefault() in a second remote place. So I'm thinking that handling it
in aclexplode() would be better.+1. It would be a really bad idea for the acldefault() logic to be
duplicated someplace else, especially in SQL code where grepping for the
relevant macros wouldn't even find it.
I figured the best and most flexible way to address this is to export
acldefault() as an SQL function and replace
aclexplode(proacl)
with
aclexplode(coalesce(proacl, acldefault('f', proowner)))
where 'f' here is something that is mapped to ACL_OBJECT_FUNCTION
internally. AFAICT, there is no existing way to map an SQL-accessible
quantity to the ACL_OBJECT_* symbols, so I'll just have to make
something up.
WIP patch is attached. If there are no objections to this approach,
I'll finish it up.
Attachments:
infoschema-aclexplode-acldefault.patchtext/x-patch; charset=UTF-8; name=infoschema-aclexplode-acldefault.patchDownload
diff --git i/src/backend/catalog/information_schema.sql w/src/backend/catalog/information_schema.sql
index b60409f..cdc6e29 100644
--- i/src/backend/catalog/information_schema.sql
+++ w/src/backend/catalog/information_schema.sql
@@ -1276,7 +1276,7 @@ CREATE VIEW routine_privileges AS
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
FROM (
- SELECT oid, proname, proowner, pronamespace, (aclexplode(proacl)).* FROM pg_proc
+ SELECT oid, proname, proowner, pronamespace, (aclexplode(coalesce(proacl, acldefault('f', proowner)))).* FROM pg_proc
) p (oid, proname, proowner, pronamespace, grantor, grantee, prtype, grantable),
pg_namespace n,
pg_authid u_grantor,
diff --git i/src/backend/utils/adt/acl.c w/src/backend/utils/adt/acl.c
index 59587c6..e48faea 100644
--- i/src/backend/utils/adt/acl.c
+++ w/src/backend/utils/adt/acl.c
@@ -833,6 +833,26 @@ acldefault(GrantObjectType objtype, Oid ownerId)
return acl;
}
+Datum
+acldefault_sql(PG_FUNCTION_ARGS)
+{
+ char objtypec = PG_GETARG_CHAR(0);
+ Oid owner = PG_GETARG_OID(1);
+ GrantObjectType objtype;
+
+ switch (objtypec)
+ {
+ case 'f':
+ objtype = ACL_OBJECT_FUNCTION;
+ break;
+ default:
+ elog(ERROR, "booh!");
+ abort();
+ }
+
+ PG_RETURN_ACL_P(acldefault(objtype, owner));
+}
+
/*
* Update an ACL array to add or remove specified privileges.
diff --git i/src/include/catalog/pg_proc.h w/src/include/catalog/pg_proc.h
index c893c3a..885e03a 100644
--- i/src/include/catalog/pg_proc.h
+++ w/src/include/catalog/pg_proc.h
@@ -1092,6 +1092,8 @@ DESCR("contains");
DATA(insert OID = 1062 ( aclitemeq PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "1033 1033" _null_ _null_ _null_ _null_ aclitem_eq _null_ _null_ _null_ ));
DATA(insert OID = 1365 ( makeaclitem PGNSP PGUID 12 1 0 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 = 3943 ( acldefault PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 1034 "18 26" _null_ _null_ _null_ _null_ acldefault_sql _null_ _null_ _null_ ));
+DESCR("TODO");
DATA(insert OID = 1689 ( aclexplode PGNSP PGUID 12 1 10 0 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 0 f f f t f i 3 0 1042 "2275 26 23" _null_ _null_ _null_ _null_ bpcharin _null_ _null_ _null_ ));
diff --git i/src/include/utils/acl.h w/src/include/utils/acl.h
index f231951..d92d348 100644
--- i/src/include/utils/acl.h
+++ w/src/include/utils/acl.h
@@ -245,6 +245,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 acldefault_sql(PG_FUNCTION_ARGS);
extern Datum aclexplode(PG_FUNCTION_ARGS);
/*
On Jan 1, 2012, at 10:43 PM, Peter Eisentraut wrote:
I figured the best and most flexible way to address this is to export
acldefault() as an SQL function and replaceaclexplode(proacl)
with
aclexplode(coalesce(proacl, acldefault('f', proowner)))
It would be nice to provide a convenience function that does the coalesce for you. End users sometimes need this stuff as well as info_schema.
--
Jim C. Nasby, Database Architect jim@nasby.net
512.569.9461 (cell) http://jim.nasby.net
On mån, 2012-01-02 at 06:43 +0200, Peter Eisentraut wrote:
I figured the best and most flexible way to address this is to export
acldefault() as an SQL function and replaceaclexplode(proacl)
with
aclexplode(coalesce(proacl, acldefault('f', proowner)))
where 'f' here is something that is mapped to ACL_OBJECT_FUNCTION
internally. AFAICT, there is no existing way to map an SQL-accessible
quantity to the ACL_OBJECT_* symbols, so I'll just have to make
something up.
Nobody had a better idea, so here is the final patch. I adjusted the
regression tests a bit to avoid bloat from the now-visible owner
privileges.
Attachments:
infoschema-aclexplode-acldefault.patchtext/x-patch; charset=UTF-8; name=infoschema-aclexplode-acldefault.patchDownload
diff --git i/src/backend/catalog/information_schema.sql w/src/backend/catalog/information_schema.sql
index 8185828..f591f64 100644
--- i/src/backend/catalog/information_schema.sql
+++ w/src/backend/catalog/information_schema.sql
@@ -554,7 +554,7 @@ CREATE VIEW column_privileges AS
pr_c.prtype,
pr_c.grantable,
pr_c.relowner
- FROM (SELECT oid, relname, relnamespace, relowner, (aclexplode(relacl)).*
+ FROM (SELECT oid, relname, relnamespace, relowner, (aclexplode(coalesce(relacl, acldefault('r', relowner)))).*
FROM pg_class
WHERE relkind IN ('r', 'v', 'f')
) pr_c (oid, relname, relnamespace, relowner, grantor, grantee, prtype, grantable),
@@ -571,8 +571,8 @@ CREATE VIEW column_privileges AS
pr_a.prtype,
pr_a.grantable,
c.relowner
- FROM (SELECT attrelid, attname, (aclexplode(attacl)).*
- FROM pg_attribute
+ FROM (SELECT attrelid, attname, (aclexplode(coalesce(attacl, acldefault('c', relowner)))).*
+ FROM pg_attribute a JOIN pg_class cc ON (a.attrelid = cc.oid)
WHERE attnum > 0
AND NOT attisdropped
) pr_a (attrelid, attname, grantor, grantee, prtype, grantable),
@@ -1276,7 +1276,7 @@ CREATE VIEW routine_privileges AS
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
FROM (
- SELECT oid, proname, proowner, pronamespace, (aclexplode(proacl)).* FROM pg_proc
+ SELECT oid, proname, proowner, pronamespace, (aclexplode(coalesce(proacl, acldefault('f', proowner)))).* FROM pg_proc
) p (oid, proname, proowner, pronamespace, grantor, grantee, prtype, grantable),
pg_namespace n,
pg_authid u_grantor,
@@ -1797,7 +1797,7 @@ CREATE VIEW table_privileges AS
CAST(CASE WHEN c.prtype = 'SELECT' THEN 'YES' ELSE 'NO' END AS yes_or_no) AS with_hierarchy
FROM (
- SELECT oid, relname, relnamespace, relkind, relowner, (aclexplode(relacl)).* FROM pg_class
+ SELECT oid, relname, relnamespace, relkind, relowner, (aclexplode(coalesce(relacl, acldefault('r', relowner)))).* FROM pg_class
) AS c (oid, relname, relnamespace, relkind, relowner, grantor, grantee, prtype, grantable),
pg_namespace nc,
pg_authid u_grantor,
@@ -2043,7 +2043,7 @@ CREATE VIEW udt_privileges AS
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
FROM (
- SELECT oid, typname, typnamespace, typtype, typowner, (aclexplode(typacl)).* FROM pg_type
+ SELECT oid, typname, typnamespace, typtype, typowner, (aclexplode(coalesce(typacl, acldefault('T', typowner)))).* FROM pg_type
) AS t (oid, typname, typnamespace, typtype, typowner, grantor, grantee, prtype, grantable),
pg_namespace n,
pg_authid u_grantor,
@@ -2129,7 +2129,7 @@ CREATE VIEW usage_privileges AS
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
FROM (
- SELECT oid, typname, typnamespace, typtype, typowner, (aclexplode(typacl)).* FROM pg_type
+ SELECT oid, typname, typnamespace, typtype, typowner, (aclexplode(coalesce(typacl, acldefault('T', typowner)))).* FROM pg_type
) AS t (oid, typname, typnamespace, typtype, typowner, grantor, grantee, prtype, grantable),
pg_namespace n,
pg_authid u_grantor,
@@ -2166,7 +2166,7 @@ CREATE VIEW usage_privileges AS
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
FROM (
- SELECT fdwname, fdwowner, (aclexplode(fdwacl)).* FROM pg_foreign_data_wrapper
+ SELECT fdwname, fdwowner, (aclexplode(coalesce(fdwacl, acldefault('F', fdwowner)))).* FROM pg_foreign_data_wrapper
) AS fdw (fdwname, fdwowner, grantor, grantee, prtype, grantable),
pg_authid u_grantor,
(
@@ -2200,7 +2200,7 @@ CREATE VIEW usage_privileges AS
THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_grantable
FROM (
- SELECT srvname, srvowner, (aclexplode(srvacl)).* FROM pg_foreign_server
+ SELECT srvname, srvowner, (aclexplode(coalesce(srvacl, acldefault('S', srvowner)))).* FROM pg_foreign_server
) AS srv (srvname, srvowner, grantor, grantee, prtype, grantable),
pg_authid u_grantor,
(
diff --git i/src/backend/utils/adt/acl.c w/src/backend/utils/adt/acl.c
index b80fc44..9644afc 100644
--- i/src/backend/utils/adt/acl.c
+++ w/src/backend/utils/adt/acl.c
@@ -835,6 +835,64 @@ acldefault(GrantObjectType objtype, Oid ownerId)
/*
+ * SQL-accessible version of acldefault(). Hackish mapping from "char" type to
+ * ACL_OBJECT_* values, but it's only used in the information schema, not
+ * documented for general use.
+ */
+Datum
+acldefault_sql(PG_FUNCTION_ARGS)
+{
+ char objtypec = PG_GETARG_CHAR(0);
+ Oid owner = PG_GETARG_OID(1);
+ GrantObjectType objtype = 0;
+
+ switch (objtypec)
+ {
+ case 'c':
+ objtype = ACL_OBJECT_COLUMN;
+ break;
+ case 'r':
+ objtype = ACL_OBJECT_RELATION;
+ break;
+ case 's':
+ objtype = ACL_OBJECT_SEQUENCE;
+ break;
+ case 'd':
+ objtype = ACL_OBJECT_DATABASE;
+ break;
+ case 'f':
+ objtype = ACL_OBJECT_FUNCTION;
+ break;
+ case 'l':
+ objtype = ACL_OBJECT_LANGUAGE;
+ break;
+ case 'L':
+ objtype = ACL_OBJECT_LARGEOBJECT;
+ break;
+ case 'n':
+ objtype = ACL_OBJECT_NAMESPACE;
+ break;
+ case 't':
+ objtype = ACL_OBJECT_TABLESPACE;
+ break;
+ case 'F':
+ objtype = ACL_OBJECT_FDW;
+ break;
+ case 'S':
+ objtype = ACL_OBJECT_FOREIGN_SERVER;
+ break;
+ case 'T':
+ objtype = ACL_OBJECT_TYPE;
+ break;
+ default:
+ elog(ERROR, "unrecognized objtype abbreviation: %c", objtypec);
+ }
+
+ PG_RETURN_ACL_P(acldefault(objtype, owner));
+}
+
+
+/*
* Update an ACL array to add or remove specified privileges.
*
* old_acl: the input ACL array
diff --git i/src/include/catalog/pg_proc.h w/src/include/catalog/pg_proc.h
index 355c61a..43f9d4f 100644
--- i/src/include/catalog/pg_proc.h
+++ w/src/include/catalog/pg_proc.h
@@ -1092,6 +1092,8 @@ DESCR("contains");
DATA(insert OID = 1062 ( aclitemeq PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "1033 1033" _null_ _null_ _null_ _null_ aclitem_eq _null_ _null_ _null_ ));
DATA(insert OID = 1365 ( makeaclitem PGNSP PGUID 12 1 0 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 = 3943 ( acldefault PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 1034 "18 26" _null_ _null_ _null_ _null_ acldefault_sql _null_ _null_ _null_ ));
+DESCR("TODO");
DATA(insert OID = 1689 ( aclexplode PGNSP PGUID 12 1 10 0 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 0 f f f t f i 3 0 1042 "2275 26 23" _null_ _null_ _null_ _null_ bpcharin _null_ _null_ _null_ ));
diff --git i/src/include/utils/acl.h w/src/include/utils/acl.h
index 88a66cf..ff3c6aa 100644
--- i/src/include/utils/acl.h
+++ w/src/include/utils/acl.h
@@ -245,6 +245,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 acldefault_sql(PG_FUNCTION_ARGS);
extern Datum aclexplode(PG_FUNCTION_ARGS);
/*
diff --git i/src/test/regress/expected/foreign_data.out w/src/test/regress/expected/foreign_data.out
index 2a6e876..d497e59 100644
--- i/src/test/regress/expected/foreign_data.out
+++ w/src/test/regress/expected/foreign_data.out
@@ -852,7 +852,7 @@ SELECT * FROM information_schema.user_mapping_options ORDER BY lower(authorizati
regress_test_role | regression | t1 | username | bob
(7 rows)
-SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' AND object_name IN ('s6', 'foo') ORDER BY 1, 2, 3, 4, 5;
grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable
-------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+--------------
foreign_data_user | foreign_data_user | regression | | foo | FOREIGN DATA WRAPPER | USAGE | YES
@@ -861,7 +861,7 @@ SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIG
foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES
(4 rows)
-SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' AND object_name IN ('s6', 'foo') ORDER BY 1, 2, 3, 4, 5;
grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable
-------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+--------------
foreign_data_user | foreign_data_user | regression | | foo | FOREIGN DATA WRAPPER | USAGE | YES
@@ -895,14 +895,14 @@ SELECT * FROM information_schema.user_mapping_options ORDER BY 1, 2, 3, 4;
regress_test_role | regression | t1 | username | bob
(5 rows)
-SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' AND object_name IN ('s6', 'foo') ORDER BY 1, 2, 3, 4, 5;
grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable
-------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+--------------
foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES
(2 rows)
-SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' AND object_name IN ('s6', 'foo') ORDER BY 1, 2, 3, 4, 5;
grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable
-------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+--------------
foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
diff --git i/src/test/regress/sql/foreign_data.sql w/src/test/regress/sql/foreign_data.sql
index 95d02d1..41ca46c 100644
--- i/src/test/regress/sql/foreign_data.sql
+++ w/src/test/regress/sql/foreign_data.sql
@@ -336,14 +336,14 @@ SELECT * FROM information_schema.foreign_servers ORDER BY 1, 2;
SELECT * FROM information_schema.foreign_server_options ORDER BY 1, 2, 3;
SELECT * FROM information_schema.user_mappings ORDER BY lower(authorization_identifier), 2, 3;
SELECT * FROM information_schema.user_mapping_options ORDER BY lower(authorization_identifier), 2, 3, 4;
-SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
-SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' AND object_name IN ('s6', 'foo') ORDER BY 1, 2, 3, 4, 5;
+SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' AND object_name IN ('s6', 'foo') ORDER BY 1, 2, 3, 4, 5;
SELECT * FROM information_schema.foreign_tables ORDER BY 1, 2, 3;
SELECT * FROM information_schema.foreign_table_options ORDER BY 1, 2, 3, 4;
SET ROLE regress_test_role;
SELECT * FROM information_schema.user_mapping_options ORDER BY 1, 2, 3, 4;
-SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
-SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' AND object_name IN ('s6', 'foo') ORDER BY 1, 2, 3, 4, 5;
+SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' AND object_name IN ('s6', 'foo') ORDER BY 1, 2, 3, 4, 5;
DROP USER MAPPING FOR current_user SERVER t1;
SET ROLE regress_test_role2;
SELECT * FROM information_schema.user_mapping_options ORDER BY 1, 2, 3, 4;
At 2012-01-09 20:23:59 +0200, peter_e@gmx.net wrote:
Nobody had a better idea, so here is the final patch. I adjusted the
regression tests a bit to avoid bloat from the now-visible owner
privileges.
Patch applies, builds, and passes tests (and does report EXECUTE
privileges on a newly-created function). Code looks fine.
-- ams
On Mon, Jan 09, 2012 at 08:23:59PM +0200, Peter Eisentraut wrote:
On mᅵn, 2012-01-02 at 06:43 +0200, Peter Eisentraut wrote:
I figured the best and most flexible way to address this is to export
acldefault() as an SQL function and replace
aclexplode(proacl)
with
aclexplode(coalesce(proacl, acldefault('f', proowner)))
Nobody had a better idea, so here is the final patch.
Thanks! This is important for the LibreOffice-PostgreSQL integration,
since LibreOffice uses the privilege information to determine whether
to let the user edit/insert data in the UI or not. It is thus
important for this information to be correct.
I currently work around that with a UNION, assuming that the default
acl is "owner has all rights".
--
Lionel