/* OCLASS_USER_MAPPING */
{ "user mapping", OBJECT_USER_MAPPING },
/* OCLASS_DEFACL */
- { "default acl", -1 }, /* unmapped */
+ { "default acl", OBJECT_DEFACL },
/* OCLASS_EXTENSION */
{ "extension", OBJECT_EXTENSION },
/* OCLASS_EVENT_TRIGGER */
List *objargs, bool missing_ok);
static ObjectAddress get_object_address_usermapping(List *objname,
List *objargs, bool missing_ok);
+static ObjectAddress get_object_address_defacl(List *objname, List *objargs,
+ bool missing_ok);
static const ObjectPropertyType *get_object_property_data(Oid class_id);
static void getRelationDescription(StringInfo buffer, Oid relid);
address = get_object_address_usermapping(objname, objargs,
missing_ok);
break;
+ case OBJECT_DEFACL:
+ address = get_object_address_defacl(objname, objargs,
+ missing_ok);
+ break;
default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
/* placate compiler, in case it thinks elog might return */
return address;
}
+/*
+ * Find the ObjectAddress for a default ACL.
+ */
+static ObjectAddress
+get_object_address_defacl(List *objname, List *objargs, bool missing_ok)
+{
+ HeapTuple tp;
+ Oid userid;
+ Oid schemaid;
+ char *username;
+ char *schema;
+ char objtype;
+ char *objtype_str;
+ ObjectAddress address;
+
+ ObjectAddressSet(address, DefaultAclRelationId, InvalidOid);
+
+ /*
+ * First figure out the textual attributes so that they can be used for
+ * error reporting.
+ */
+ username = strVal(linitial(objname));
+ if (list_length(objname) >= 2)
+ schema = (char *) strVal(lsecond(objname));
+ else
+ schema = NULL;
+
+ /*
+ * Decode defaclobjtype. Only first char is considered; the rest of the
+ * string, if any, is blissfully ignored.
+ */
+ objtype = ((char *) strVal(linitial(objargs)))[0];
+ switch (objtype)
+ {
+ case DEFACLOBJ_RELATION:
+ objtype_str = "tables";
+ break;
+ case DEFACLOBJ_SEQUENCE:
+ objtype_str = "sequences";
+ break;
+ case DEFACLOBJ_FUNCTION:
+ objtype_str = "functions";
+ break;
+ case DEFACLOBJ_TYPE:
+ objtype_str = "types";
+ break;
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized default ACL object type %c", objtype),
+ errhint("Valid object types are 'r', 'S', 'f', and 'T'.")));
+ }
+
+ /*
+ * Look up user ID. Behave as "default ACL not found" if the user doesn't
+ * exist.
+ */
+ tp = SearchSysCache1(AUTHNAME,
+ CStringGetDatum(username));
+ if (!HeapTupleIsValid(tp))
+ goto not_found;
+ userid = HeapTupleGetOid(tp);
+ ReleaseSysCache(tp);
+
+ /*
+ * If a schema name was given, look up its OID. If it doesn't exist,
+ * behave as "default ACL not found".
+ */
+ if (schema)
+ {
+ schemaid = get_namespace_oid(schema, true);
+ if (schemaid == InvalidOid)
+ goto not_found;
+ }
+ else
+ schemaid = InvalidOid;
+
+ /* Finally, look up the pg_default_acl object */
+ tp = SearchSysCache3(DEFACLROLENSPOBJ,
+ ObjectIdGetDatum(userid),
+ ObjectIdGetDatum(schemaid),
+ CharGetDatum(objtype));
+ if (!HeapTupleIsValid(tp))
+ goto not_found;
+
+ address.objectId = HeapTupleGetOid(tp);
+ ReleaseSysCache(tp);
+
+ return address;
+
+not_found:
+ if (!missing_ok)
+ {
+ if (schema)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("default ACL for user \"%s\" in schema \"%s\" on %s does not exist",
+ username, schema, objtype_str)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("default ACL for user \"%s\" on %s does not exist",
+ username, objtype_str)));
+ }
+ return address;
+}
+
/*
* Convert an array of TEXT into a List of string Values, as emitted by the
* parser, which is what get_object_address uses as input.
case OBJECT_OPFAMILY:
case OBJECT_CAST:
case OBJECT_USER_MAPPING:
+ case OBJECT_DEFACL:
if (list_length(args) != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
SysScanDesc rcscan;
HeapTuple tup;
Form_pg_default_acl defacl;
-
- /* no objname support */
- if (objname)
- *objname = NIL;
+ char *schema;
+ char *username;
defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
defacl = (Form_pg_default_acl) GETSTRUCT(tup);
+ username = GetUserNameFromId(defacl->defaclrole);
appendStringInfo(&buffer,
"for role %s",
- quote_identifier(GetUserNameFromId(defacl->defaclrole)));
+ quote_identifier(username));
if (OidIsValid(defacl->defaclnamespace))
{
- char *schema;
-
schema = get_namespace_name(defacl->defaclnamespace);
appendStringInfo(&buffer,
" in schema %s",
quote_identifier(schema));
}
+ else
+ schema = NULL;
switch (defacl->defaclobjtype)
{
break;
}
+ if (objname)
+ {
+ *objname = list_make1(username);
+ if (schema)
+ *objname = lappend(*objname, schema);
+ *objargs = list_make1(psprintf("%c", defacl->defaclobjtype));
+ }
+
systable_endscan(rcscan);
heap_close(defaclrel, AccessShareLock);
break;
case OBJECT_COLUMN:
case OBJECT_COLLATION:
case OBJECT_CONVERSION:
+ case OBJECT_DEFACL:
case OBJECT_DEFAULT:
case OBJECT_DOMAIN:
case OBJECT_DOMCONSTRAINT:
OBJECT_CONVERSION,
OBJECT_DATABASE,
OBJECT_DEFAULT,
+ OBJECT_DEFACL,
OBJECT_DOMAIN,
OBJECT_DOMCONSTRAINT,
OBJECT_EVENT_TRIGGER,
NOTICE: test_event_trigger: ddl_command_end CREATE SERVER
create user mapping for regression_bob server useless_server;
NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING
+alter default privileges for role regression_bob
+ revoke delete on tables from regression_bob;
+NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES
-- alter owner to non-superuser should fail
alter event trigger regress_event_trigger owner to regression_bob;
ERROR: permission denied to change owner of event trigger "regress_event_trigger"
drop role regression_bob;
ERROR: role "regression_bob" cannot be dropped because some objects depend on it
DETAIL: owner of event trigger regress_event_trigger3
+owner of default privileges on new relations belonging to role regression_bob
owner of user mapping for regression_bob on server useless_server
-- cleanup before next test
-- these are all OK; the second one should emit a NOTICE
CREATE POLICY genpol ON addr_nsp.gentable;
CREATE SERVER "integer" FOREIGN DATA WRAPPER addr_fdw;
CREATE USER MAPPING FOR regtest_addr_user SERVER "integer";
+ALTER DEFAULT PRIVILEGES FOR ROLE regtest_addr_user IN SCHEMA public GRANT ALL ON TABLES TO regtest_addr_user;
+ALTER DEFAULT PRIVILEGES FOR ROLE regtest_addr_user REVOKE DELETE ON TABLES FROM regtest_addr_user;
-- test some error cases
SELECT pg_get_object_address('stone', '{}', '{}');
ERROR: unrecognized object type "stone"
('operator'), ('operator class'), ('operator family'), ('rule'), ('trigger'),
('text search parser'), ('text search dictionary'),
('text search template'), ('text search configuration'),
- ('policy'), ('user mapping')
+ ('policy'), ('user mapping'), ('default acl')
LOOP
FOR names IN VALUES ('{eins}'), ('{addr_nsp, zwei}'), ('{eins, zwei, drei}')
LOOP
WARNING: error for user mapping,{addr_nsp,zwei},{integer}: user mapping for user "addr_nsp" in server "integer" does not exist
WARNING: error for user mapping,{eins,zwei,drei},{}: argument list length must be exactly 1
WARNING: error for user mapping,{eins,zwei,drei},{integer}: user mapping for user "eins" in server "integer" does not exist
+WARNING: error for default acl,{eins},{}: argument list length must be exactly 1
+WARNING: error for default acl,{eins},{integer}: unrecognized default ACL object type i
+WARNING: error for default acl,{addr_nsp,zwei},{}: argument list length must be exactly 1
+WARNING: error for default acl,{addr_nsp,zwei},{integer}: unrecognized default ACL object type i
+WARNING: error for default acl,{eins,zwei,drei},{}: argument list length must be exactly 1
+WARNING: error for default acl,{eins,zwei,drei},{integer}: unrecognized default ACL object type i
-- these object types cannot be qualified names
SELECT pg_get_object_address('language', '{one}', '{}');
ERROR: language "one" does not exist
('foreign-data wrapper', '{addr_fdw}', '{}'),
('server', '{addr_fserv}', '{}'),
('user mapping', '{regtest_addr_user}', '{integer}'),
+ ('default acl', '{regtest_addr_user,public}', '{r}'),
+ ('default acl', '{regtest_addr_user}', '{r}'),
-- extension
-- event trigger
('policy', '{addr_nsp, gentable, genpol}', '{}')
ORDER BY addr1.classid, addr1.objid;
type | schema | name | identity | ?column?
---------------------------+------------+-------------------+----------------------------------------------------------------------+----------
+ default acl | | | for role regtest_addr_user in schema public on tables | t
+ default acl | | | for role regtest_addr_user on tables | t
type | pg_catalog | _int4 | integer[] | t
type | addr_nsp | gencomptype | addr_nsp.gencomptype | t
type | addr_nsp | genenum | addr_nsp.genenum | t
text search parser | addr_nsp | addr_ts_prs | addr_nsp.addr_ts_prs | t
text search configuration | addr_nsp | addr_ts_conf | addr_nsp.addr_ts_conf | t
text search template | addr_nsp | addr_ts_temp | addr_nsp.addr_ts_temp | t
-(36 rows)
+(38 rows)
---
--- Cleanup resources
---
DROP FOREIGN DATA WRAPPER addr_fdw CASCADE;
DROP SCHEMA addr_nsp CASCADE;
+DROP OWNED BY regtest_addr_user;
DROP USER regtest_addr_user;
create foreign data wrapper useless;
create server useless_server foreign data wrapper useless;
create user mapping for regression_bob server useless_server;
+alter default privileges for role regression_bob
+ revoke delete on tables from regression_bob;
-- alter owner to non-superuser should fail
alter event trigger regress_event_trigger owner to regression_bob;
CREATE POLICY genpol ON addr_nsp.gentable;
CREATE SERVER "integer" FOREIGN DATA WRAPPER addr_fdw;
CREATE USER MAPPING FOR regtest_addr_user SERVER "integer";
+ALTER DEFAULT PRIVILEGES FOR ROLE regtest_addr_user IN SCHEMA public GRANT ALL ON TABLES TO regtest_addr_user;
+ALTER DEFAULT PRIVILEGES FOR ROLE regtest_addr_user REVOKE DELETE ON TABLES FROM regtest_addr_user;
-- test some error cases
SELECT pg_get_object_address('stone', '{}', '{}');
('operator'), ('operator class'), ('operator family'), ('rule'), ('trigger'),
('text search parser'), ('text search dictionary'),
('text search template'), ('text search configuration'),
- ('policy'), ('user mapping')
+ ('policy'), ('user mapping'), ('default acl')
LOOP
FOR names IN VALUES ('{eins}'), ('{addr_nsp, zwei}'), ('{eins, zwei, drei}')
LOOP
('foreign-data wrapper', '{addr_fdw}', '{}'),
('server', '{addr_fserv}', '{}'),
('user mapping', '{regtest_addr_user}', '{integer}'),
+ ('default acl', '{regtest_addr_user,public}', '{r}'),
+ ('default acl', '{regtest_addr_user}', '{r}'),
-- extension
-- event trigger
('policy', '{addr_nsp, gentable, genpol}', '{}')
DROP SCHEMA addr_nsp CASCADE;
+DROP OWNED BY regtest_addr_user;
DROP USER regtest_addr_user;