Skip to content

Commit 890192e

Browse files
committed
Support user mappings in get_object_address
Since commit 72dd233 we were trying to obtain object addressing information in sql_drop event triggers, but that caused failures when the drops involved user mappings. This addition enables that to work again. Naturally, pg_get_object_address can work with these objects now, too. I toyed with the idea of removing DropUserMappingStmt as a node and using DropStmt instead in the DropUserMappingStmt grammar production, but that didn't go very well: for one thing the messages thrown by the specific code are specialized (you get "server not found" if you specify the wrong server, instead of a generic "user mapping for ... not found" which you'd get it we were to merge this with RemoveObjects --- unless we added even more special cases). For another thing, it would require to pass RoleSpec nodes through the objname/objargs representation used by RemoveObjects, which works in isolation, but gets messy when pg_get_object_address is involved. So I dropped this part for now. Reviewed by Stephen Frost.
1 parent 1ce7a57 commit 890192e

File tree

7 files changed

+109
-13
lines changed

7 files changed

+109
-13
lines changed

src/backend/catalog/objectaddress.c

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ ObjectTypeMap[] =
520520
/* OCLASS_FOREIGN_SERVER */
521521
{ "server", OBJECT_FOREIGN_SERVER },
522522
/* OCLASS_USER_MAPPING */
523-
{ "user mapping", -1 }, /* unmapped */
523+
{ "user mapping", OBJECT_USER_MAPPING },
524524
/* OCLASS_DEFACL */
525525
{ "default acl", -1 }, /* unmapped */
526526
/* OCLASS_EXTENSION */
@@ -555,6 +555,8 @@ static ObjectAddress get_object_address_type(ObjectType objtype,
555555
List *objname, bool missing_ok);
556556
static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
557557
List *objargs, bool missing_ok);
558+
static ObjectAddress get_object_address_usermapping(List *objname,
559+
List *objargs, bool missing_ok);
558560
static const ObjectPropertyType *get_object_property_data(Oid class_id);
559561

560562
static void getRelationDescription(StringInfo buffer, Oid relid);
@@ -769,6 +771,10 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
769771
address.objectId = get_ts_config_oid(objname, missing_ok);
770772
address.objectSubId = 0;
771773
break;
774+
case OBJECT_USER_MAPPING:
775+
address = get_object_address_usermapping(objname, objargs,
776+
missing_ok);
777+
break;
772778
default:
773779
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
774780
/* placate compiler, in case it thinks elog might return */
@@ -1372,6 +1378,75 @@ get_object_address_opcf(ObjectType objtype,
13721378
return address;
13731379
}
13741380

1381+
/*
1382+
* Find the ObjectAddress for a user mapping.
1383+
*/
1384+
static ObjectAddress
1385+
get_object_address_usermapping(List *objname, List *objargs, bool missing_ok)
1386+
{
1387+
ObjectAddress address;
1388+
Oid userid;
1389+
char *username;
1390+
char *servername;
1391+
ForeignServer *server;
1392+
HeapTuple tp;
1393+
1394+
ObjectAddressSet(address, UserMappingRelationId, InvalidOid);
1395+
1396+
/* fetch string names from input lists, for error messages */
1397+
username = strVal(linitial(objname));
1398+
servername = strVal(linitial(objargs));
1399+
1400+
/* look up pg_authid OID of mapped user; InvalidOid if PUBLIC */
1401+
if (strcmp(username, "public") == 0)
1402+
userid = InvalidOid;
1403+
else
1404+
{
1405+
tp = SearchSysCache1(AUTHNAME,
1406+
CStringGetDatum(username));
1407+
if (!HeapTupleIsValid(tp))
1408+
{
1409+
if (!missing_ok)
1410+
ereport(ERROR,
1411+
(errcode(ERRCODE_UNDEFINED_OBJECT),
1412+
errmsg("user mapping for user \"%s\" in server \"%s\" does not exist",
1413+
username, servername)));
1414+
return address;
1415+
}
1416+
userid = HeapTupleGetOid(tp);
1417+
ReleaseSysCache(tp);
1418+
}
1419+
1420+
/* Now look up the pg_user_mapping tuple */
1421+
server = GetForeignServerByName(servername, true);
1422+
if (!server)
1423+
{
1424+
if (!missing_ok)
1425+
ereport(ERROR,
1426+
(errcode(ERRCODE_UNDEFINED_OBJECT),
1427+
errmsg("server \"%s\" does not exist", servername)));
1428+
return address;
1429+
}
1430+
tp = SearchSysCache2(USERMAPPINGUSERSERVER,
1431+
ObjectIdGetDatum(userid),
1432+
ObjectIdGetDatum(server->serverid));
1433+
if (!HeapTupleIsValid(tp))
1434+
{
1435+
if (!missing_ok)
1436+
ereport(ERROR,
1437+
(errcode(ERRCODE_UNDEFINED_OBJECT),
1438+
errmsg("user mapping for user \"%s\" in server \"%s\" does not exist",
1439+
username, servername)));
1440+
return address;
1441+
}
1442+
1443+
address.objectId = HeapTupleGetOid(tp);
1444+
1445+
ReleaseSysCache(tp);
1446+
1447+
return address;
1448+
}
1449+
13751450
/*
13761451
* Convert an array of TEXT into a List of string Values, as emitted by the
13771452
* parser, which is what get_object_address uses as input.
@@ -1523,6 +1598,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
15231598
case OBJECT_OPCLASS:
15241599
case OBJECT_OPFAMILY:
15251600
case OBJECT_CAST:
1601+
case OBJECT_USER_MAPPING:
15261602
if (list_length(args) != 1)
15271603
ereport(ERROR,
15281604
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),

src/backend/commands/event_trigger.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,7 @@ EventTriggerSupportsObjectType(ObjectType obtype)
10921092
case OBJECT_TSPARSER:
10931093
case OBJECT_TSTEMPLATE:
10941094
case OBJECT_TYPE:
1095+
case OBJECT_USER_MAPPING:
10951096
case OBJECT_VIEW:
10961097
return true;
10971098
}

src/include/nodes/parsenodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,6 +1268,7 @@ typedef enum ObjectType
12681268
OBJECT_TSPARSER,
12691269
OBJECT_TSTEMPLATE,
12701270
OBJECT_TYPE,
1271+
OBJECT_USER_MAPPING,
12711272
OBJECT_VIEW
12721273
} ObjectType;
12731274

src/test/regress/expected/event_trigger.out

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ revoke all on table event_trigger_fire1 from public;
110110
NOTICE: test_event_trigger: ddl_command_end REVOKE
111111
drop table event_trigger_fire1;
112112
NOTICE: test_event_trigger: ddl_command_end DROP TABLE
113+
create foreign data wrapper useless;
114+
NOTICE: test_event_trigger: ddl_command_end CREATE FOREIGN DATA WRAPPER
115+
create server useless_server foreign data wrapper useless;
116+
NOTICE: test_event_trigger: ddl_command_end CREATE SERVER
117+
create user mapping for regression_bob server useless_server;
118+
NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING
113119
-- alter owner to non-superuser should fail
114120
alter event trigger regress_event_trigger owner to regression_bob;
115121
ERROR: permission denied to change owner of event trigger "regress_event_trigger"
@@ -125,10 +131,11 @@ alter event trigger regress_event_trigger rename to regress_event_trigger3;
125131
-- should fail, doesn't exist any more
126132
drop event trigger regress_event_trigger;
127133
ERROR: event trigger "regress_event_trigger" does not exist
128-
-- should fail, regression_bob owns regress_event_trigger2/3
134+
-- should fail, regression_bob owns some objects
129135
drop role regression_bob;
130136
ERROR: role "regression_bob" cannot be dropped because some objects depend on it
131137
DETAIL: owner of event trigger regress_event_trigger3
138+
owner of user mapping for regression_bob on server useless_server
132139
-- cleanup before next test
133140
-- these are all OK; the second one should emit a NOTICE
134141
drop event trigger if exists regress_event_trigger2;

src/test/regress/expected/object_address.out

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ CREATE DOMAIN addr_nsp.gendomain AS int4 CONSTRAINT domconstr CHECK (value > 0);
2828
CREATE FUNCTION addr_nsp.trig() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN END; $$;
2929
CREATE TRIGGER t BEFORE INSERT ON addr_nsp.gentable FOR EACH ROW EXECUTE PROCEDURE addr_nsp.trig();
3030
CREATE POLICY genpol ON addr_nsp.gentable;
31+
CREATE SERVER "integer" FOREIGN DATA WRAPPER addr_fdw;
32+
CREATE USER MAPPING FOR regtest_addr_user SERVER "integer";
3133
-- test some error cases
3234
SELECT pg_get_object_address('stone', '{}', '{}');
3335
ERROR: unrecognized object type "stone"
@@ -42,8 +44,7 @@ DECLARE
4244
BEGIN
4345
FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
4446
('toast table column'), ('view column'), ('materialized view column'),
45-
('operator of access method'), ('function of access method'),
46-
('user mapping')
47+
('operator of access method'), ('function of access method')
4748
LOOP
4849
BEGIN
4950
PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -61,7 +62,6 @@ WARNING: error for view column: unsupported object type "view column"
6162
WARNING: error for materialized view column: unsupported object type "materialized view column"
6263
WARNING: error for operator of access method: unsupported object type "operator of access method"
6364
WARNING: error for function of access method: unsupported object type "function of access method"
64-
WARNING: error for user mapping: unsupported object type "user mapping"
6565
DO $$
6666
DECLARE
6767
objtype text;
@@ -77,7 +77,7 @@ BEGIN
7777
('operator'), ('operator class'), ('operator family'), ('rule'), ('trigger'),
7878
('text search parser'), ('text search dictionary'),
7979
('text search template'), ('text search configuration'),
80-
('policy')
80+
('policy'), ('user mapping')
8181
LOOP
8282
FOR names IN VALUES ('{eins}'), ('{addr_nsp, zwei}'), ('{eins, zwei, drei}')
8383
LOOP
@@ -249,6 +249,12 @@ WARNING: error for policy,{addr_nsp,zwei},{}: relation "addr_nsp" does not exis
249249
WARNING: error for policy,{addr_nsp,zwei},{integer}: relation "addr_nsp" does not exist
250250
WARNING: error for policy,{eins,zwei,drei},{}: schema "eins" does not exist
251251
WARNING: error for policy,{eins,zwei,drei},{integer}: schema "eins" does not exist
252+
WARNING: error for user mapping,{eins},{}: argument list length must be exactly 1
253+
WARNING: error for user mapping,{eins},{integer}: user mapping for user "eins" in server "integer" does not exist
254+
WARNING: error for user mapping,{addr_nsp,zwei},{}: argument list length must be exactly 1
255+
WARNING: error for user mapping,{addr_nsp,zwei},{integer}: user mapping for user "addr_nsp" in server "integer" does not exist
256+
WARNING: error for user mapping,{eins,zwei,drei},{}: argument list length must be exactly 1
257+
WARNING: error for user mapping,{eins,zwei,drei},{integer}: user mapping for user "eins" in server "integer" does not exist
252258
-- these object types cannot be qualified names
253259
SELECT pg_get_object_address('language', '{one}', '{}');
254260
ERROR: language "one" does not exist
@@ -334,7 +340,7 @@ WITH objects (type, name, args) AS (VALUES
334340
-- tablespace
335341
('foreign-data wrapper', '{addr_fdw}', '{}'),
336342
('server', '{addr_fserv}', '{}'),
337-
-- user mapping
343+
('user mapping', '{regtest_addr_user}', '{integer}'),
338344
-- extension
339345
-- event trigger
340346
('policy', '{addr_nsp, gentable, genpol}', '{}')
@@ -365,6 +371,7 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*,
365371
foreign table | addr_nsp | genftable | addr_nsp.genftable | t
366372
role | | regtest_addr_user | regtest_addr_user | t
367373
server | | addr_fserv | addr_fserv | t
374+
user mapping | | | regtest_addr_user on server integer | t
368375
foreign-data wrapper | | addr_fdw | addr_fdw | t
369376
default value | | | for addr_nsp.gentable.b | t
370377
cast | | | (bigint AS integer) | t
@@ -384,7 +391,7 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*,
384391
text search parser | addr_nsp | addr_ts_prs | addr_nsp.addr_ts_prs | t
385392
text search configuration | addr_nsp | addr_ts_conf | addr_nsp.addr_ts_conf | t
386393
text search template | addr_nsp | addr_ts_temp | addr_nsp.addr_ts_temp | t
387-
(35 rows)
394+
(36 rows)
388395

389396
---
390397
--- Cleanup resources

src/test/regress/sql/event_trigger.sql

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ grant all on table event_trigger_fire1 to public;
107107
comment on table event_trigger_fire1 is 'here is a comment';
108108
revoke all on table event_trigger_fire1 from public;
109109
drop table event_trigger_fire1;
110+
create foreign data wrapper useless;
111+
create server useless_server foreign data wrapper useless;
112+
create user mapping for regression_bob server useless_server;
110113

111114
-- alter owner to non-superuser should fail
112115
alter event trigger regress_event_trigger owner to regression_bob;
@@ -124,7 +127,7 @@ alter event trigger regress_event_trigger rename to regress_event_trigger3;
124127
-- should fail, doesn't exist any more
125128
drop event trigger regress_event_trigger;
126129

127-
-- should fail, regression_bob owns regress_event_trigger2/3
130+
-- should fail, regression_bob owns some objects
128131
drop role regression_bob;
129132

130133
-- cleanup before next test

src/test/regress/sql/object_address.sql

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ CREATE DOMAIN addr_nsp.gendomain AS int4 CONSTRAINT domconstr CHECK (value > 0);
3232
CREATE FUNCTION addr_nsp.trig() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN END; $$;
3333
CREATE TRIGGER t BEFORE INSERT ON addr_nsp.gentable FOR EACH ROW EXECUTE PROCEDURE addr_nsp.trig();
3434
CREATE POLICY genpol ON addr_nsp.gentable;
35+
CREATE SERVER "integer" FOREIGN DATA WRAPPER addr_fdw;
36+
CREATE USER MAPPING FOR regtest_addr_user SERVER "integer";
3537

3638
-- test some error cases
3739
SELECT pg_get_object_address('stone', '{}', '{}');
@@ -45,8 +47,7 @@ DECLARE
4547
BEGIN
4648
FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'),
4749
('toast table column'), ('view column'), ('materialized view column'),
48-
('operator of access method'), ('function of access method'),
49-
('user mapping')
50+
('operator of access method'), ('function of access method')
5051
LOOP
5152
BEGIN
5253
PERFORM pg_get_object_address(objtype, '{one}', '{}');
@@ -72,7 +73,7 @@ BEGIN
7273
('operator'), ('operator class'), ('operator family'), ('rule'), ('trigger'),
7374
('text search parser'), ('text search dictionary'),
7475
('text search template'), ('text search configuration'),
75-
('policy')
76+
('policy'), ('user mapping')
7677
LOOP
7778
FOR names IN VALUES ('{eins}'), ('{addr_nsp, zwei}'), ('{eins, zwei, drei}')
7879
LOOP
@@ -154,7 +155,7 @@ WITH objects (type, name, args) AS (VALUES
154155
-- tablespace
155156
('foreign-data wrapper', '{addr_fdw}', '{}'),
156157
('server', '{addr_fserv}', '{}'),
157-
-- user mapping
158+
('user mapping', '{regtest_addr_user}', '{integer}'),
158159
-- extension
159160
-- event trigger
160161
('policy', '{addr_nsp, gentable, genpol}', '{}')

0 commit comments

Comments
 (0)