This is extracted from the DDL deparse series. These patches add get_object_address support for the following object types:
- user mappings - default ACLs - operators and functions of operator families In each case I had to create a new value in ObjectType. These object types can not be created from the parser, which is why they don't exist yet. But if we want to be able to process DDL for them, then we need to cope at this level. This is the kind of fix we need to handle the failures related to commit a486841eb11517e. There is one strange thing in the last one, which is that an opfamily member is represented in two arrays like this (objname, objargs): {opfamily identity, access method identity, number} , {left type, right type} This is a bit odd considering that operator families themselves are addressed like this instead: {opfamily identity} , {access method identity} Note that the AM name is originally in objargs and moves to objnames. The reason I did it this way is that the objargs elements can be processed completely as an array of TypeName, and therefore there's no need for an extra strange case in pg_get_object_address. But it does mean that there is some code that knows to search the strategy or function number in a specific position in the objname array. If we had more freedom on general object representation I'm sure we could do better, but it's what we have. I don't think it's a tremendous problem, considering that get_object_address gets a fairly ad-hoc representation for each object type anyway, as each gets constructed by the grammar. -- Álvaro Herrera http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
>From fad598488c0c15e0962808ad13825374e8a3640e Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Thu, 5 Mar 2015 12:04:39 -0300 Subject: [PATCH 1/3] deparse/core: get_object_address support user mappings --- src/backend/catalog/objectaddress.c | 67 +++++++++++++++++++++++++++- src/backend/commands/event_trigger.c | 1 + src/include/nodes/parsenodes.h | 1 + src/test/regress/expected/event_trigger.out | 12 ++++- src/test/regress/expected/object_address.out | 19 +++++--- src/test/regress/sql/event_trigger.sql | 11 ++++- src/test/regress/sql/object_address.sql | 9 ++-- 7 files changed, 107 insertions(+), 13 deletions(-) diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 541912b..5553ec7 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -520,7 +520,7 @@ ObjectTypeMap[] = /* OCLASS_FOREIGN_SERVER */ { "server", OBJECT_FOREIGN_SERVER }, /* OCLASS_USER_MAPPING */ - { "user mapping", -1 }, /* unmapped */ + { "user mapping", OBJECT_USER_MAPPING }, /* OCLASS_DEFACL */ { "default acl", -1 }, /* unmapped */ /* OCLASS_EXTENSION */ @@ -555,6 +555,8 @@ static ObjectAddress get_object_address_type(ObjectType objtype, List *objname, bool missing_ok); static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname, List *objargs, bool missing_ok); +static ObjectAddress get_object_address_usermapping(List *objname, + List *objargs, bool missing_ok); static const ObjectPropertyType *get_object_property_data(Oid class_id); static void getRelationDescription(StringInfo buffer, Oid relid); @@ -769,6 +771,10 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, address.objectId = get_ts_config_oid(objname, missing_ok); address.objectSubId = 0; break; + case OBJECT_USER_MAPPING: + address = get_object_address_usermapping(objname, objargs, + missing_ok); + break; default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); /* placate compiler, in case it thinks elog might return */ @@ -1373,6 +1379,64 @@ get_object_address_opcf(ObjectType objtype, } /* + * Find the ObjectAddress for a user mapping. + */ +static ObjectAddress +get_object_address_usermapping(List *objname, List *objargs, bool missing_ok) +{ + ObjectAddress address; + Oid userid; + char *username; + char *servername; + ForeignServer *server; + HeapTuple tp; + + ObjectAddressSet(address, UserMappingRelationId, InvalidOid); + + username = strVal(linitial(objname)); + servername = strVal(linitial(objargs)); + server = GetForeignServerByName(servername, false); + + if (strcmp(username, "public") == 0) + userid = InvalidOid; + else + { + tp = SearchSysCache1(AUTHNAME, + CStringGetDatum(username)); + if (!HeapTupleIsValid(tp)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("user mapping for user \"%s\" in server \"%s\" does not exist", + username, servername))); + return address; + } + userid = HeapTupleGetOid(tp); + ReleaseSysCache(tp); + } + + tp = SearchSysCache2(USERMAPPINGUSERSERVER, + ObjectIdGetDatum(userid), + ObjectIdGetDatum(server->serverid)); + if (!HeapTupleIsValid(tp)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("user mapping for user \"%s\" in server \"%s\" does not exist", + username, servername))); + return address; + } + + address.objectId = HeapTupleGetOid(tp); + + ReleaseSysCache(tp); + + 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. */ @@ -1523,6 +1587,7 @@ pg_get_object_address(PG_FUNCTION_ARGS) case OBJECT_OPCLASS: case OBJECT_OPFAMILY: case OBJECT_CAST: + case OBJECT_USER_MAPPING: if (list_length(args) != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index f573c9c..4e446bd 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -1092,6 +1092,7 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: case OBJECT_TYPE: + case OBJECT_USER_MAPPING: case OBJECT_VIEW: return true; } diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index ac13302..dbde840 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1248,6 +1248,7 @@ typedef enum ObjectType OBJECT_TSPARSER, OBJECT_TSTEMPLATE, OBJECT_TYPE, + OBJECT_USER_MAPPING, OBJECT_VIEW } ObjectType; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index c330ad2..4ff7f35 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -113,6 +113,15 @@ NOTICE: test_event_trigger: ddl_command_end REVOKE -- regress_event_trigger_end should fire here drop table event_trigger_fire1; NOTICE: test_event_trigger: ddl_command_end DROP TABLE +-- regress_event_trigger_end should fire here +create foreign data wrapper useless; +NOTICE: test_event_trigger: ddl_command_end CREATE FOREIGN DATA WRAPPER +-- regress_event_trigger_end should fire here +create server useless_server foreign data wrapper useless; +NOTICE: test_event_trigger: ddl_command_end CREATE SERVER +-- regress_event_trigger_end should fire here +create user mapping for regression_bob server useless_server; +NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING -- 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" @@ -128,10 +137,11 @@ alter event trigger regress_event_trigger rename to regress_event_trigger3; -- should fail, doesn't exist any more drop event trigger regress_event_trigger; ERROR: event trigger "regress_event_trigger" does not exist --- should fail, regression_bob owns regress_event_trigger2/3 +-- should fail, regression_bob owns some objects 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 user mapping for regression_bob on server useless_server -- cleanup before next test -- these are all OK; the second one should emit a NOTICE drop event trigger if exists regress_event_trigger2; diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index dcf1b46..e72abda 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -28,6 +28,8 @@ CREATE DOMAIN addr_nsp.gendomain AS int4 CONSTRAINT domconstr CHECK (value > 0); CREATE FUNCTION addr_nsp.trig() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN END; $$; CREATE TRIGGER t BEFORE INSERT ON addr_nsp.gentable FOR EACH ROW EXECUTE PROCEDURE addr_nsp.trig(); CREATE POLICY genpol ON addr_nsp.gentable; +CREATE SERVER "integer" FOREIGN DATA WRAPPER addr_fdw; +CREATE USER MAPPING FOR regtest_addr_user SERVER "integer"; -- test some error cases SELECT pg_get_object_address('stone', '{}', '{}'); ERROR: unrecognized object type "stone" @@ -42,8 +44,7 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('operator of access method'), ('function of access method'), - ('user mapping') + ('operator of access method'), ('function of access method') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -61,7 +62,6 @@ WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for operator of access method: unsupported object type "operator of access method" WARNING: error for function of access method: unsupported object type "function of access method" -WARNING: error for user mapping: unsupported object type "user mapping" DO $$ DECLARE objtype text; @@ -77,7 +77,7 @@ BEGIN ('operator'), ('operator class'), ('operator family'), ('rule'), ('trigger'), ('text search parser'), ('text search dictionary'), ('text search template'), ('text search configuration'), - ('policy') + ('policy'), ('user mapping') LOOP FOR names IN VALUES ('{eins}'), ('{addr_nsp, zwei}'), ('{eins, zwei, drei}') LOOP @@ -249,6 +249,12 @@ WARNING: error for policy,{addr_nsp,zwei},{}: relation "addr_nsp" does not exis WARNING: error for policy,{addr_nsp,zwei},{integer}: relation "addr_nsp" does not exist WARNING: error for policy,{eins,zwei,drei},{}: schema "eins" does not exist WARNING: error for policy,{eins,zwei,drei},{integer}: schema "eins" does not exist +WARNING: error for user mapping,{eins},{}: argument list length must be exactly 1 +WARNING: error for user mapping,{eins},{integer}: user mapping for user "eins" in server "integer" does not exist +WARNING: error for user mapping,{addr_nsp,zwei},{}: argument list length must be exactly 1 +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 -- these object types cannot be qualified names SELECT pg_get_object_address('language', '{one}', '{}'); ERROR: language "one" does not exist @@ -334,7 +340,7 @@ WITH objects (type, name, args) AS (VALUES -- tablespace ('foreign-data wrapper', '{addr_fdw}', '{}'), ('server', '{addr_fserv}', '{}'), - -- user mapping + ('user mapping', '{regtest_addr_user}', '{integer}'), -- extension -- event trigger ('policy', '{addr_nsp, gentable, genpol}', '{}') @@ -365,6 +371,7 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*, foreign table | addr_nsp | genftable | addr_nsp.genftable | t role | | regtest_addr_user | regtest_addr_user | t server | | addr_fserv | addr_fserv | t + user mapping | | | regtest_addr_user on server integer | t foreign-data wrapper | | addr_fdw | addr_fdw | t default value | | | for addr_nsp.gentable.b | t cast | | | (bigint AS integer) | t @@ -384,7 +391,7 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*, 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 -(35 rows) +(36 rows) --- --- Cleanup resources diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index fd4c332..f89fa71 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -114,6 +114,15 @@ revoke all on table event_trigger_fire1 from public; -- regress_event_trigger_end should fire here drop table event_trigger_fire1; +-- regress_event_trigger_end should fire here +create foreign data wrapper useless; + +-- regress_event_trigger_end should fire here +create server useless_server foreign data wrapper useless; + +-- regress_event_trigger_end should fire here +create user mapping for regression_bob server useless_server; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regression_bob; @@ -130,7 +139,7 @@ alter event trigger regress_event_trigger rename to regress_event_trigger3; -- should fail, doesn't exist any more drop event trigger regress_event_trigger; --- should fail, regression_bob owns regress_event_trigger2/3 +-- should fail, regression_bob owns some objects drop role regression_bob; -- cleanup before next test diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 9fc27d8..b714b52 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -32,6 +32,8 @@ CREATE DOMAIN addr_nsp.gendomain AS int4 CONSTRAINT domconstr CHECK (value > 0); CREATE FUNCTION addr_nsp.trig() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN END; $$; CREATE TRIGGER t BEFORE INSERT ON addr_nsp.gentable FOR EACH ROW EXECUTE PROCEDURE addr_nsp.trig(); CREATE POLICY genpol ON addr_nsp.gentable; +CREATE SERVER "integer" FOREIGN DATA WRAPPER addr_fdw; +CREATE USER MAPPING FOR regtest_addr_user SERVER "integer"; -- test some error cases SELECT pg_get_object_address('stone', '{}', '{}'); @@ -45,8 +47,7 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('operator of access method'), ('function of access method'), - ('user mapping') + ('operator of access method'), ('function of access method') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -72,7 +73,7 @@ BEGIN ('operator'), ('operator class'), ('operator family'), ('rule'), ('trigger'), ('text search parser'), ('text search dictionary'), ('text search template'), ('text search configuration'), - ('policy') + ('policy'), ('user mapping') LOOP FOR names IN VALUES ('{eins}'), ('{addr_nsp, zwei}'), ('{eins, zwei, drei}') LOOP @@ -154,7 +155,7 @@ WITH objects (type, name, args) AS (VALUES -- tablespace ('foreign-data wrapper', '{addr_fdw}', '{}'), ('server', '{addr_fserv}', '{}'), - -- user mapping + ('user mapping', '{regtest_addr_user}', '{integer}'), -- extension -- event trigger ('policy', '{addr_nsp, gentable, genpol}', '{}') -- 2.1.4
>From 21c30e970b1d22482660dfcc154767f3b5c03ae4 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Fri, 6 Mar 2015 17:16:29 -0300 Subject: [PATCH 2/3] deparse/core: get_object_address support default ACLs --- src/backend/catalog/objectaddress.c | 125 +++++++++++++++++++++++++-- src/backend/commands/event_trigger.c | 1 + src/include/nodes/parsenodes.h | 1 + src/test/regress/expected/event_trigger.out | 5 ++ src/test/regress/expected/object_address.out | 17 +++- src/test/regress/sql/event_trigger.sql | 4 + src/test/regress/sql/object_address.sql | 7 +- 7 files changed, 149 insertions(+), 11 deletions(-) diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 5553ec7..32eea58 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -522,7 +522,7 @@ ObjectTypeMap[] = /* 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 */ @@ -557,6 +557,8 @@ static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname, 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); @@ -775,6 +777,10 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, 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 */ @@ -1437,6 +1443,95 @@ get_object_address_usermapping(List *objname, List *objargs, bool missing_ok) } /* + * 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 objtyp; + char *stuff; + ObjectAddress address; + + ObjectAddressSet(address, DefaultAclRelationId, InvalidOid); + + /* + * Figure out the textual attributes first so that they can be used for + * error reporting. + */ + username = strVal(linitial(objname)); + if (list_length(objargs) >= 2) + schema = (char *) strVal(llast(objargs)); + else + schema = NULL; + + objtyp = ((char *) strVal(linitial(objargs)))[0]; + switch (objtyp) + { + case DEFACLOBJ_RELATION: + stuff = "tables"; + break; + case DEFACLOBJ_SEQUENCE: + stuff = "sequences"; + break; + case DEFACLOBJ_FUNCTION: + stuff = "functions"; + break; + case DEFACLOBJ_TYPE: + stuff = "types"; + break; + default: + elog(ERROR, "invalid defacl type %c", objtyp); + } + + tp = SearchSysCache1(AUTHNAME, + CStringGetDatum(username)); + if (!HeapTupleIsValid(tp)) + goto not_found; + + userid = HeapTupleGetOid(tp); + ReleaseSysCache(tp); + + if (schema) + { + schemaid = get_namespace_oid(schema, true); + if (schemaid == InvalidOid) + goto not_found; + } + else + schemaid = InvalidOid; + + tp = SearchSysCache3(DEFACLROLENSPOBJ, + ObjectIdGetDatum(userid), + ObjectIdGetDatum(schemaid), + CharGetDatum(objtyp)); + if (!HeapTupleIsValid(tp)) + goto not_found; + + address.objectId = HeapTupleGetOid(tp); + ReleaseSysCache(tp); + + return address; + +not_found: + if (schema) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("default ACL for user \"%s\" in schema \"%s\" on %s does not exist", + username, schema, stuff))); + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("default ACL for user \"%s\" on %s does not exist", + username, stuff))); + 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. */ @@ -1599,6 +1694,13 @@ pg_get_object_address(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument list length must be exactly %d", 2))); break; + case OBJECT_DEFACL: + if ((list_length(args) < 1) || + (list_length(args) > 2)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("argument list length must be between %d and %d", 1, 2))); + break; default: break; } @@ -4013,10 +4115,8 @@ getObjectIdentityParts(const ObjectAddress *object, 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); @@ -4036,19 +4136,20 @@ getObjectIdentityParts(const ObjectAddress *object, 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) { @@ -4070,6 +4171,14 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + if (objname) + { + *objname = list_make1(username); + *objargs = list_make1(psprintf("%c", defacl->defaclobjtype)); + if (schema) + *objargs = lappend(*objargs, schema); + } + systable_endscan(rcscan); heap_close(defaclrel, AccessShareLock); break; diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 4e446bd..3fec57e 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -1065,6 +1065,7 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_COLUMN: case OBJECT_COLLATION: case OBJECT_CONVERSION: + case OBJECT_DEFACL: case OBJECT_DEFAULT: case OBJECT_DOMAIN: case OBJECT_DOMCONSTRAINT: diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index dbde840..36c5d43 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1219,6 +1219,7 @@ typedef enum ObjectType OBJECT_CONVERSION, OBJECT_DATABASE, OBJECT_DEFAULT, + OBJECT_DEFACL, OBJECT_DOMAIN, OBJECT_DOMCONSTRAINT, OBJECT_EVENT_TRIGGER, diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 4ff7f35..47dc023 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -122,6 +122,10 @@ NOTICE: test_event_trigger: ddl_command_end CREATE SERVER -- regress_event_trigger_end should fire here create user mapping for regression_bob server useless_server; NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING +-- regress_event_trigger_end should fire here +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" @@ -141,6 +145,7 @@ ERROR: event trigger "regress_event_trigger" does not exist 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 diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index e72abda..e7bb06a 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -30,6 +30,8 @@ CREATE TRIGGER t BEFORE INSERT ON addr_nsp.gentable FOR EACH ROW EXECUTE PROCEDU 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" @@ -77,7 +79,7 @@ BEGIN ('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 @@ -255,6 +257,12 @@ WARNING: error for user mapping,{addr_nsp,zwei},{}: argument list length must b 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 between 1 and 2 +WARNING: error for default acl,{eins},{integer}: invalid defacl type i +WARNING: error for default acl,{addr_nsp,zwei},{}: argument list length must be between 1 and 2 +WARNING: error for default acl,{addr_nsp,zwei},{integer}: invalid defacl type i +WARNING: error for default acl,{eins,zwei,drei},{}: argument list length must be between 1 and 2 +WARNING: error for default acl,{eins,zwei,drei},{integer}: invalid defacl type i -- these object types cannot be qualified names SELECT pg_get_object_address('language', '{one}', '{}'); ERROR: language "one" does not exist @@ -341,6 +349,8 @@ WITH objects (type, name, args) AS (VALUES ('foreign-data wrapper', '{addr_fdw}', '{}'), ('server', '{addr_fserv}', '{}'), ('user mapping', '{regtest_addr_user}', '{integer}'), + ('default acl', '{regtest_addr_user}', '{r,public}'), + ('default acl', '{regtest_addr_user}', '{r}'), -- extension -- event trigger ('policy', '{addr_nsp, gentable, genpol}', '{}') @@ -355,6 +365,8 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*, 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 @@ -391,11 +403,12 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*, 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; diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index f89fa71..2569a6c 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -123,6 +123,10 @@ create server useless_server foreign data wrapper useless; -- regress_event_trigger_end should fire here create user mapping for regression_bob server useless_server; +-- regress_event_trigger_end should fire here +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; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index b714b52..f4d940c 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -34,6 +34,8 @@ CREATE TRIGGER t BEFORE INSERT ON addr_nsp.gentable FOR EACH ROW EXECUTE PROCEDU 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', '{}', '{}'); @@ -73,7 +75,7 @@ BEGIN ('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 @@ -156,6 +158,8 @@ WITH objects (type, name, args) AS (VALUES ('foreign-data wrapper', '{addr_fdw}', '{}'), ('server', '{addr_fserv}', '{}'), ('user mapping', '{regtest_addr_user}', '{integer}'), + ('default acl', '{regtest_addr_user}', '{r,public}'), + ('default acl', '{regtest_addr_user}', '{r}'), -- extension -- event trigger ('policy', '{addr_nsp, gentable, genpol}', '{}') @@ -176,4 +180,5 @@ DROP FOREIGN DATA WRAPPER addr_fdw CASCADE; DROP SCHEMA addr_nsp CASCADE; +DROP OWNED BY regtest_addr_user; DROP USER regtest_addr_user; -- 2.1.4
>From 2f13e09885c3fed6afd3654a01815a45ba74f34f Mon Sep 17 00:00:00 2001 From: Alvaro Herrera <alvhe...@alvh.no-ip.org> Date: Fri, 6 Mar 2015 12:39:50 -0300 Subject: [PATCH 3/3] deparse/core: get_object_address support opfamily members --- src/backend/catalog/objectaddress.c | 180 ++++++++++++++++++++++++--- src/backend/commands/event_trigger.c | 2 + src/include/nodes/parsenodes.h | 2 + src/test/regress/expected/object_address.out | 32 +++-- src/test/regress/sql/object_address.sql | 12 +- 5 files changed, 194 insertions(+), 34 deletions(-) diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 32eea58..b6cde3e 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -492,9 +492,9 @@ ObjectTypeMap[] = /* OCLASS_OPFAMILY */ { "operator family", OBJECT_OPFAMILY }, /* OCLASS_AMOP */ - { "operator of access method", -1 }, /* unmapped */ + { "operator of access method", OBJECT_AMOP }, /* OCLASS_AMPROC */ - { "function of access method", -1 }, /* unmapped */ + { "function of access method", OBJECT_AMPROC }, /* OCLASS_REWRITE */ { "rule", OBJECT_RULE }, /* OCLASS_TRIGGER */ @@ -552,9 +552,12 @@ static ObjectAddress get_object_address_attrdef(ObjectType objtype, List *objname, Relation *relp, LOCKMODE lockmode, bool missing_ok); static ObjectAddress get_object_address_type(ObjectType objtype, - List *objname, bool missing_ok); + ListCell *typecell, bool missing_ok); static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname, List *objargs, bool missing_ok); +static ObjectAddress get_object_address_opf_member(ObjectType objtype, + List *objname, 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, @@ -661,7 +664,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, ObjectAddress domaddr; char *constrname; - domaddr = get_object_address_type(OBJECT_DOMAIN, objname, missing_ok); + domaddr = get_object_address_type(OBJECT_DOMAIN, + list_head(objname), missing_ok); constrname = strVal(linitial(objargs)); address.classId = ConstraintRelationId; @@ -685,7 +689,7 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, break; case OBJECT_TYPE: case OBJECT_DOMAIN: - address = get_object_address_type(objtype, objname, missing_ok); + address = get_object_address_type(objtype, list_head(objname), missing_ok); break; case OBJECT_AGGREGATE: address.classId = ProcedureRelationId; @@ -724,6 +728,11 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, address = get_object_address_opcf(objtype, objname, objargs, missing_ok); break; + case OBJECT_AMOP: + case OBJECT_AMPROC: + address = get_object_address_opf_member(objtype, objname, + objargs, missing_ok); + break; case OBJECT_LARGEOBJECT: Assert(list_length(objname) == 1); address.classId = LargeObjectRelationId; @@ -1309,13 +1318,13 @@ get_object_address_attrdef(ObjectType objtype, List *objname, * Find the ObjectAddress for a type or domain */ static ObjectAddress -get_object_address_type(ObjectType objtype, List *objname, bool missing_ok) +get_object_address_type(ObjectType objtype, ListCell *typecell, bool missing_ok) { ObjectAddress address; TypeName *typename; Type tup; - typename = (TypeName *) linitial(objname); + typename = (TypeName *) lfirst(typecell); address.classId = TypeRelationId; address.objectId = InvalidOid; @@ -1384,6 +1393,116 @@ get_object_address_opcf(ObjectType objtype, return address; } +static ObjectAddress +get_object_address_opf_member(ObjectType objtype, + List *objname, List *objargs, bool missing_ok) +{ + ObjectAddress famaddr; + ObjectAddress typaddr; + ObjectAddress address; + ListCell *cell; + Value *amname; + List *copy; + List *amlist; + Oid lefttype; + Oid righttype; + int stratnum; + char *leftname; + char *rightname; + + /* + * last element of the objname list contains the AM name; previous-to-last + * contains the strategy or procedure number; elements prior to that contain the + * (possibly qualified) opfamily name. Create a copy of the list that we + * can scribble on to extract those values. + */ + copy = list_copy(objname); + amname = lfirst(list_tail(copy)); + amlist = list_make1(amname); + copy = list_truncate(copy, list_length(copy) - 1); + + stratnum = atoi(strVal(llast(copy))); + copy = list_truncate(copy, list_length(copy) - 1); + + /* no missing_ok support here */ + famaddr = get_object_address_opcf(OBJECT_OPFAMILY, copy, amlist, false); + + cell = list_head(objargs); + leftname = strVal(cell); + typaddr = get_object_address_type(OBJECT_TYPE, cell, missing_ok); + lefttype = typaddr.objectId; + + cell = lnext(cell); + typaddr = get_object_address_type(OBJECT_TYPE, cell, missing_ok); + rightname = strVal(cell); + righttype = typaddr.objectId; + + switch (objtype) + { + case OBJECT_AMOP: + { + HeapTuple tp; + + ObjectAddressSet(address, AccessMethodOperatorRelationId, + InvalidOid); + + tp = SearchSysCache4(AMOPSTRATEGY, + ObjectIdGetDatum(famaddr.objectId), + ObjectIdGetDatum(lefttype), + ObjectIdGetDatum(righttype), + Int16GetDatum(stratnum)); + if (!HeapTupleIsValid(tp)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("operator %d (%s, %s) of %s does not exist", + stratnum, leftname, rightname, + getObjectDescription(&famaddr)))); + } + else + { + address.objectId = HeapTupleGetOid(tp); + ReleaseSysCache(tp); + } + } + break; + + case OBJECT_AMPROC: + { + HeapTuple tp; + + ObjectAddressSet(address, AccessMethodProcedureRelationId, + InvalidOid); + + tp = SearchSysCache4(AMPROCNUM, + ObjectIdGetDatum(famaddr.objectId), + ObjectIdGetDatum(lefttype), + ObjectIdGetDatum(righttype), + Int16GetDatum(stratnum)); + if (!HeapTupleIsValid(tp)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("function %d (%s, %s) of %s does not exist", + stratnum, leftname, rightname, + getObjectDescription(&famaddr)))); + } + else + { + address.objectId = HeapTupleGetOid(tp); + ReleaseSysCache(tp); + } + } + break; + default: + elog(ERROR, "unrecognized objtype: %d", (int) objtype); + } + + return address; +} + /* * Find the ObjectAddress for a user mapping. */ @@ -1644,7 +1763,9 @@ pg_get_object_address(PG_FUNCTION_ARGS) if (type == OBJECT_AGGREGATE || type == OBJECT_FUNCTION || type == OBJECT_OPERATOR || - type == OBJECT_CAST) + type == OBJECT_CAST || + type == OBJECT_AMOP || + type == OBJECT_AMPROC) { /* in these cases, the args list must be of TypeName */ Datum *elems; @@ -1688,6 +1809,13 @@ pg_get_object_address(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument list length must be exactly %d", 1))); break; + case OBJECT_AMOP: + case OBJECT_AMPROC: + if (list_length(name) < 2) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("name list length must be at least %d", 2))); + /* fall through to check args length */ case OBJECT_OPERATOR: if (list_length(args) != 2) ereport(ERROR, @@ -3736,10 +3864,6 @@ getObjectIdentityParts(const ObjectAddress *object, Form_pg_amop amopForm; StringInfoData opfam; - /* no objname support here */ - if (objname) - *objname = NIL; - amopDesc = heap_open(AccessMethodOperatorRelationId, AccessShareLock); @@ -3760,7 +3884,19 @@ getObjectIdentityParts(const ObjectAddress *object, amopForm = (Form_pg_amop) GETSTRUCT(tup); initStringInfo(&opfam); - getOpFamilyIdentity(&opfam, amopForm->amopfamily, NULL, NULL); + getOpFamilyIdentity(&opfam, amopForm->amopfamily, objname, objargs); + + if (objname) + { + *objname = lappend(*objname, + psprintf("%d", amopForm->amopstrategy)); + *objname = lappend(*objname, + llast(*objargs)); + *objargs = lappend(NIL, + format_type_be_qualified(amopForm->amoplefttype)); + *objargs = lappend(*objargs, + format_type_be_qualified(amopForm->amoprighttype)); + } appendStringInfo(&buffer, "operator %d (%s, %s) of %s", amopForm->amopstrategy, @@ -3784,10 +3920,6 @@ getObjectIdentityParts(const ObjectAddress *object, Form_pg_amproc amprocForm; StringInfoData opfam; - /* no objname support here */ - if (objname) - *objname = NIL; - amprocDesc = heap_open(AccessMethodProcedureRelationId, AccessShareLock); @@ -3808,7 +3940,19 @@ getObjectIdentityParts(const ObjectAddress *object, amprocForm = (Form_pg_amproc) GETSTRUCT(tup); initStringInfo(&opfam); - getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, NULL, NULL); + getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, objname, objargs); + + if (objname) + { + *objname = lappend(*objname, + psprintf("%d", amprocForm->amprocnum)); + *objname = lappend(*objname, + llast(*objargs)); + *objargs = lappend(NIL, + format_type_be_qualified(amprocForm->amproclefttype)); + *objargs = lappend(*objargs, + format_type_be_qualified(amprocForm->amprocrighttype)); + } appendStringInfo(&buffer, "function %d (%s, %s) of %s", amprocForm->amprocnum, diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 3fec57e..4bcc327 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -1060,6 +1060,8 @@ EventTriggerSupportsObjectType(ObjectType obtype) /* no support for event triggers on event triggers */ return false; case OBJECT_AGGREGATE: + case OBJECT_AMOP: + case OBJECT_AMPROC: case OBJECT_ATTRIBUTE: case OBJECT_CAST: case OBJECT_COLUMN: diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 36c5d43..d969640 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1212,6 +1212,8 @@ typedef struct SetOperationStmt typedef enum ObjectType { OBJECT_AGGREGATE, + OBJECT_AMOP, + OBJECT_AMPROC, OBJECT_ATTRIBUTE, /* type's attribute, when distinct from column */ OBJECT_CAST, OBJECT_COLUMN, diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index e7bb06a..c85f643 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -45,8 +45,7 @@ DECLARE objtype text; BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), - ('toast table column'), ('view column'), ('materialized view column'), - ('operator of access method'), ('function of access method') + ('toast table column'), ('view column'), ('materialized view column') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -62,8 +61,6 @@ WARNING: error for sequence column: unsupported object type "sequence column" WARNING: error for toast table column: unsupported object type "toast table column" WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" -WARNING: error for operator of access method: unsupported object type "operator of access method" -WARNING: error for function of access method: unsupported object type "function of access method" DO $$ DECLARE objtype text; @@ -79,7 +76,8 @@ BEGIN ('operator'), ('operator class'), ('operator family'), ('rule'), ('trigger'), ('text search parser'), ('text search dictionary'), ('text search template'), ('text search configuration'), - ('policy'), ('user mapping'), ('default acl') + ('policy'), ('user mapping'), ('default acl'), + ('operator of access method'), ('function of access method') LOOP FOR names IN VALUES ('{eins}'), ('{addr_nsp, zwei}'), ('{eins, zwei, drei}') LOOP @@ -263,6 +261,18 @@ WARNING: error for default acl,{addr_nsp,zwei},{}: argument list length must be WARNING: error for default acl,{addr_nsp,zwei},{integer}: invalid defacl type i WARNING: error for default acl,{eins,zwei,drei},{}: argument list length must be between 1 and 2 WARNING: error for default acl,{eins,zwei,drei},{integer}: invalid defacl type i +WARNING: error for operator of access method,{eins},{}: name list length must be at least 2 +WARNING: error for operator of access method,{eins},{integer}: name list length must be at least 2 +WARNING: error for operator of access method,{addr_nsp,zwei},{}: argument list length must be exactly 2 +WARNING: error for operator of access method,{addr_nsp,zwei},{integer}: argument list length must be exactly 2 +WARNING: error for operator of access method,{eins,zwei,drei},{}: argument list length must be exactly 2 +WARNING: error for operator of access method,{eins,zwei,drei},{integer}: argument list length must be exactly 2 +WARNING: error for function of access method,{eins},{}: name list length must be at least 2 +WARNING: error for function of access method,{eins},{integer}: name list length must be at least 2 +WARNING: error for function of access method,{addr_nsp,zwei},{}: argument list length must be exactly 2 +WARNING: error for function of access method,{addr_nsp,zwei},{integer}: argument list length must be exactly 2 +WARNING: error for function of access method,{eins,zwei,drei},{}: argument list length must be exactly 2 +WARNING: error for function of access method,{eins,zwei,drei},{integer}: argument list length must be exactly 2 -- these object types cannot be qualified names SELECT pg_get_object_address('language', '{one}', '{}'); ERROR: language "one" does not exist @@ -334,8 +344,8 @@ WITH objects (type, name, args) AS (VALUES ('operator', '{+}', '{int4, int4}'), ('operator class', '{int4_ops}', '{btree}'), ('operator family', '{integer_ops}', '{btree}'), - -- operator of access method - -- function of access method + ('operator of access method', '{integer_ops,1,btree}', '{integer,integer}'), + ('function of access method', '{integer_ops,2,btree}', '{integer,integer}'), ('rule', '{addr_nsp, genview, _RETURN}', '{}'), ('trigger', '{addr_nsp, gentable, t}', '{}'), ('schema', '{addr_nsp}', '{}'), @@ -362,7 +372,7 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*, FROM objects, pg_get_object_address(type, name, args) addr1, pg_identify_object_as_address(classid, objid, subobjid) ioa(typ,nms,args), pg_get_object_address(typ, nms, ioa.args) as addr2 - ORDER BY addr1.classid, addr1.objid; + ORDER BY addr1.classid, addr1.objid, addr1.subobjid; type | schema | name | identity | ?column? ---------------------------+------------+-------------------+----------------------------------------------------------------------+---------- default acl | | | for role regtest_addr_user in schema public on tables | t @@ -379,12 +389,14 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*, index | addr_nsp | gentable_pkey | addr_nsp.gentable_pkey | t view | addr_nsp | genview | addr_nsp.genview | t materialized view | addr_nsp | genmatview | addr_nsp.genmatview | t - foreign table column | addr_nsp | genftable | addr_nsp.genftable.a | t foreign table | addr_nsp | genftable | addr_nsp.genftable | t + foreign table column | addr_nsp | genftable | addr_nsp.genftable.a | t role | | regtest_addr_user | regtest_addr_user | t server | | addr_fserv | addr_fserv | t user mapping | | | regtest_addr_user on server integer | t foreign-data wrapper | | addr_fdw | addr_fdw | t + operator of access method | | | operator 1 (integer, integer) of pg_catalog.integer_ops USING btree | t + function of access method | | | function 2 (integer, integer) of pg_catalog.integer_ops USING btree | t default value | | | for addr_nsp.gentable.b | t cast | | | (bigint AS integer) | t table constraint | addr_nsp | | a_chk on addr_nsp.gentable | t @@ -403,7 +415,7 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*, 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 -(38 rows) +(40 rows) --- --- Cleanup resources diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index f4d940c..e1be6bf 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -48,8 +48,7 @@ DECLARE objtype text; BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), - ('toast table column'), ('view column'), ('materialized view column'), - ('operator of access method'), ('function of access method') + ('toast table column'), ('view column'), ('materialized view column') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -75,7 +74,8 @@ BEGIN ('operator'), ('operator class'), ('operator family'), ('rule'), ('trigger'), ('text search parser'), ('text search dictionary'), ('text search template'), ('text search configuration'), - ('policy'), ('user mapping'), ('default acl') + ('policy'), ('user mapping'), ('default acl'), + ('operator of access method'), ('function of access method') LOOP FOR names IN VALUES ('{eins}'), ('{addr_nsp, zwei}'), ('{eins, zwei, drei}') LOOP @@ -143,8 +143,8 @@ WITH objects (type, name, args) AS (VALUES ('operator', '{+}', '{int4, int4}'), ('operator class', '{int4_ops}', '{btree}'), ('operator family', '{integer_ops}', '{btree}'), - -- operator of access method - -- function of access method + ('operator of access method', '{integer_ops,1,btree}', '{integer,integer}'), + ('function of access method', '{integer_ops,2,btree}', '{integer,integer}'), ('rule', '{addr_nsp, genview, _RETURN}', '{}'), ('trigger', '{addr_nsp, gentable, t}', '{}'), ('schema', '{addr_nsp}', '{}'), @@ -171,7 +171,7 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.subobjid)).*, FROM objects, pg_get_object_address(type, name, args) addr1, pg_identify_object_as_address(classid, objid, subobjid) ioa(typ,nms,args), pg_get_object_address(typ, nms, ioa.args) as addr2 - ORDER BY addr1.classid, addr1.objid; + ORDER BY addr1.classid, addr1.objid, addr1.subobjid; --- --- Cleanup resources -- 2.1.4
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers