diff options
author | Alvaro Herrera | 2015-03-16 15:06:34 +0000 |
---|---|---|
committer | Alvaro Herrera | 2015-03-16 15:06:34 +0000 |
commit | a61fd5334eb1040d0dcec0368702398a5b49152c (patch) | |
tree | b7976f69848c8b072cef4104208e5834ec4d93b2 /src/backend | |
parent | 8d1f239003d0245dda636dfa6cf0add13bee69d6 (diff) |
Support opfamily members in get_object_address
In the spirit of 890192e99af and 4464303405f: have get_object_address
understand individual pg_amop and pg_amproc objects. There is no way to
refer to such objects directly in the grammar -- rather, they are almost
always considered an integral part of the opfamily that contains them.
(The only case that deals with them individually is ALTER OPERATOR
FAMILY ADD/DROP, which carries the opfamily address separately and thus
does not need it to be part of each added/dropped element's address.)
In event triggers it becomes possible to become involved with individual
amop/amproc elements, and this commit enables pg_get_object_address to
do so as well.
To make the overall coding simpler, this commit also slightly changes
the get_object_address representation for opclasses and opfamilies:
instead of having the AM name in the objargs array, I moved it as the
first element of the objnames array. This enables the new code to use
objargs for the type names used by pg_amop and pg_amproc.
Reviewed by: Stephen Frost
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/catalog/objectaddress.c | 234 | ||||
-rw-r--r-- | src/backend/commands/dropcmds.c | 24 | ||||
-rw-r--r-- | src/backend/commands/event_trigger.c | 2 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 43 |
4 files changed, 218 insertions, 85 deletions
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 142bc689e95..46ea09a6118 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); + 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, @@ -567,8 +570,7 @@ static void getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId); static void getProcedureTypeDescription(StringInfo buffer, Oid procid); static void getConstraintTypeDescription(StringInfo buffer, Oid constroid); -static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **objname, - List **objargs); +static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **objname); static void getRelationIdentity(StringInfo buffer, Oid relid, List **objname); /* @@ -661,7 +663,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 +688,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; @@ -721,8 +724,12 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, break; case OBJECT_OPCLASS: case OBJECT_OPFAMILY: - address = get_object_address_opcf(objtype, - objname, objargs, missing_ok); + address = get_object_address_opcf(objtype, objname, 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); @@ -1309,13 +1316,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; @@ -1351,15 +1358,14 @@ get_object_address_type(ObjectType objtype, List *objname, bool missing_ok) * Find the ObjectAddress for an opclass or opfamily. */ static ObjectAddress -get_object_address_opcf(ObjectType objtype, - List *objname, List *objargs, bool missing_ok) +get_object_address_opcf(ObjectType objtype, List *objname, bool missing_ok) { Oid amoid; ObjectAddress address; - Assert(list_length(objargs) == 1); /* XXX no missing_ok support here */ - amoid = get_am_oid(strVal(linitial(objargs)), false); + amoid = get_am_oid(strVal(linitial(objname)), false); + objname = list_copy_tail(objname, 1); switch (objtype) { @@ -1385,6 +1391,114 @@ get_object_address_opcf(ObjectType objtype, } /* + * Find the ObjectAddress for an opclass/opfamily member. + * + * (The returned address corresponds to a pg_amop/pg_amproc object). + */ +static ObjectAddress +get_object_address_opf_member(ObjectType objtype, + List *objname, List *objargs, bool missing_ok) +{ + ObjectAddress famaddr; + ObjectAddress address; + ListCell *cell; + List *copy; + char *typenames[2]; + Oid typeoids[2]; + int membernum; + int i; + + /* + * The last element of the objname list contains the strategy or procedure + * number. We need to strip that out before getting the opclass/family + * address. The rest can be used directly by get_object_address_opcf(). + */ + membernum = atoi(strVal(llast(objname))); + copy = list_truncate(list_copy(objname), list_length(objname) - 1); + + /* no missing_ok support here */ + famaddr = get_object_address_opcf(OBJECT_OPFAMILY, copy, false); + + /* find out left/right type names and OIDs */ + i = 0; + foreach (cell, objargs) + { + ObjectAddress typaddr; + + typenames[i] = strVal(lfirst(cell)); + typaddr = get_object_address_type(OBJECT_TYPE, cell, missing_ok); + typeoids[i] = typaddr.objectId; + if (i++ >= 2) + break; + } + + switch (objtype) + { + case OBJECT_AMOP: + { + HeapTuple tp; + + ObjectAddressSet(address, AccessMethodOperatorRelationId, + InvalidOid); + + tp = SearchSysCache4(AMOPSTRATEGY, + ObjectIdGetDatum(famaddr.objectId), + ObjectIdGetDatum(typeoids[0]), + ObjectIdGetDatum(typeoids[1]), + Int16GetDatum(membernum)); + if (!HeapTupleIsValid(tp)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("operator %d (%s, %s) of %s does not exist", + membernum, typenames[0], typenames[1], + 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(typeoids[0]), + ObjectIdGetDatum(typeoids[1]), + Int16GetDatum(membernum)); + if (!HeapTupleIsValid(tp)) + { + if (!missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("function %d (%s, %s) of %s does not exist", + membernum, typenames[0], typenames[1], + 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. */ static ObjectAddress @@ -1673,7 +1787,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; @@ -1708,8 +1824,6 @@ pg_get_object_address(PG_FUNCTION_ARGS) switch (type) { case OBJECT_DOMCONSTRAINT: - case OBJECT_OPCLASS: - case OBJECT_OPFAMILY: case OBJECT_CAST: case OBJECT_USER_MAPPING: case OBJECT_DEFACL: @@ -1718,6 +1832,20 @@ pg_get_object_address(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument list length must be exactly %d", 1))); break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + if (list_length(name) < 2) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("name list length must be at least %d", 2))); + break; + case OBJECT_AMOP: + case OBJECT_AMPROC: + if (list_length(name) < 3) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("name list length must be at least %d", 3))); + /* fall through to check args length */ case OBJECT_OPERATOR: if (list_length(args) != 2) ereport(ERROR, @@ -3730,24 +3858,22 @@ getObjectIdentityParts(const ObjectAddress *object, opcForm->opcmethod); amForm = (Form_pg_am) GETSTRUCT(amTup); - appendStringInfoString(&buffer, - quote_qualified_identifier(schema, - NameStr(opcForm->opcname))); - appendStringInfo(&buffer, " USING %s", + appendStringInfo(&buffer, "%s USING %s", + quote_qualified_identifier(schema, + NameStr(opcForm->opcname)), quote_identifier(NameStr(amForm->amname))); if (objname) - { - *objname = list_make2(pstrdup(schema), + *objname = list_make3(pstrdup(NameStr(amForm->amname)), + schema, pstrdup(NameStr(opcForm->opcname))); - *objargs = list_make1(pstrdup(NameStr(amForm->amname))); - } + ReleaseSysCache(amTup); ReleaseSysCache(opcTup); break; } case OCLASS_OPFAMILY: - getOpFamilyIdentity(&buffer, object->objectId, objname, objargs); + getOpFamilyIdentity(&buffer, object->objectId, objname); break; case OCLASS_AMOP: @@ -3758,10 +3884,8 @@ getObjectIdentityParts(const ObjectAddress *object, SysScanDesc amscan; Form_pg_amop amopForm; StringInfoData opfam; - - /* no objname support here */ - if (objname) - *objname = NIL; + char *ltype; + char *rtype; amopDesc = heap_open(AccessMethodOperatorRelationId, AccessShareLock); @@ -3783,13 +3907,21 @@ getObjectIdentityParts(const ObjectAddress *object, amopForm = (Form_pg_amop) GETSTRUCT(tup); initStringInfo(&opfam); - getOpFamilyIdentity(&opfam, amopForm->amopfamily, NULL, NULL); + getOpFamilyIdentity(&opfam, amopForm->amopfamily, objname); + + ltype = format_type_be_qualified(amopForm->amoplefttype); + rtype = format_type_be_qualified(amopForm->amoprighttype); + + if (objname) + { + *objname = lappend(*objname, + psprintf("%d", amopForm->amopstrategy)); + *objargs = list_make2(ltype, rtype); + } appendStringInfo(&buffer, "operator %d (%s, %s) of %s", amopForm->amopstrategy, - format_type_be_qualified(amopForm->amoplefttype), - format_type_be_qualified(amopForm->amoprighttype), - opfam.data); + ltype, rtype, opfam.data); pfree(opfam.data); @@ -3806,10 +3938,8 @@ getObjectIdentityParts(const ObjectAddress *object, HeapTuple tup; Form_pg_amproc amprocForm; StringInfoData opfam; - - /* no objname support here */ - if (objname) - *objname = NIL; + char *ltype; + char *rtype; amprocDesc = heap_open(AccessMethodProcedureRelationId, AccessShareLock); @@ -3831,13 +3961,21 @@ getObjectIdentityParts(const ObjectAddress *object, amprocForm = (Form_pg_amproc) GETSTRUCT(tup); initStringInfo(&opfam); - getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, NULL, NULL); + getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, objname); + + ltype = format_type_be_qualified(amprocForm->amproclefttype); + rtype = format_type_be_qualified(amprocForm->amprocrighttype); + + if (objname) + { + *objname = lappend(*objname, + psprintf("%d", amprocForm->amprocnum)); + *objargs = list_make2(ltype, rtype); + } appendStringInfo(&buffer, "function %d (%s, %s) of %s", amprocForm->amprocnum, - format_type_be_qualified(amprocForm->amproclefttype), - format_type_be_qualified(amprocForm->amprocrighttype), - opfam.data); + ltype, rtype, opfam.data); pfree(opfam.data); @@ -4263,7 +4401,7 @@ getObjectIdentityParts(const ObjectAddress *object, } static void -getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **objname, List **objargs) +getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **objname) { HeapTuple opfTup; Form_pg_opfamily opfForm; @@ -4289,11 +4427,9 @@ getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **objname, List **objargs NameStr(amForm->amname)); if (objname) - { - *objname = list_make2(pstrdup(schema), + *objname = list_make3(pstrdup(NameStr(amForm->amname)), + pstrdup(schema), pstrdup(NameStr(opfForm->opfname))); - *objargs = list_make1(pstrdup(NameStr(amForm->amname))); - } ReleaseSysCache(amTup); ReleaseSysCache(opfTup); diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index e5185ba34d2..a1b0d4d2fa2 100644 --- a/src/backend/commands/dropcmds.c +++ b/src/backend/commands/dropcmds.c @@ -406,19 +406,27 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs) name = NameListToString(objname); break; case OBJECT_OPCLASS: - if (!schema_does_not_exist_skipping(objname, &msg, &name)) { - msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping"); - name = NameListToString(objname); - args = strVal(linitial(objargs)); + List *opcname = list_copy_tail(objname, 1); + + if (!schema_does_not_exist_skipping(opcname, &msg, &name)) + { + msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping"); + name = NameListToString(opcname); + args = strVal(linitial(objname)); + } } break; case OBJECT_OPFAMILY: - if (!schema_does_not_exist_skipping(objname, &msg, &name)) { - msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping"); - name = NameListToString(objname); - args = strVal(linitial(objargs)); + List *opfname = list_copy_tail(objname, 1); + + if (!schema_does_not_exist_skipping(opfname, &msg, &name)) + { + msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping"); + name = NameListToString(opfname); + args = strVal(linitial(objname)); + } } break; default: diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 3fec57ea237..4bcc327a2b5 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/backend/parser/gram.y b/src/backend/parser/gram.y index cf0d31744e1..149962035dc 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -3950,8 +3950,7 @@ AlterExtensionContentsStmt: n->extname = $3; n->action = $4; n->objtype = OBJECT_OPCLASS; - n->objname = $7; - n->objargs = list_make1(makeString($9)); + n->objname = lcons(makeString($9), $7); $$ = (Node *)n; } | ALTER EXTENSION name add_drop OPERATOR FAMILY any_name USING access_method @@ -3960,8 +3959,7 @@ AlterExtensionContentsStmt: n->extname = $3; n->action = $4; n->objtype = OBJECT_OPFAMILY; - n->objname = $7; - n->objargs = list_make1(makeString($9)); + n->objname = lcons(makeString($9), $7); $$ = (Node *)n; } | ALTER EXTENSION name add_drop SCHEMA name @@ -5362,8 +5360,7 @@ DropOpClassStmt: DROP OPERATOR CLASS any_name USING access_method opt_drop_behavior { DropStmt *n = makeNode(DropStmt); - n->objects = list_make1($4); - n->arguments = list_make1(list_make1(makeString($6))); + n->objects = list_make1(lcons(makeString($6), $4)); n->removeType = OBJECT_OPCLASS; n->behavior = $7; n->missing_ok = false; @@ -5373,8 +5370,7 @@ DropOpClassStmt: | DROP OPERATOR CLASS IF_P EXISTS any_name USING access_method opt_drop_behavior { DropStmt *n = makeNode(DropStmt); - n->objects = list_make1($6); - n->arguments = list_make1(list_make1(makeString($8))); + n->objects = list_make1(lcons(makeString($8), $6)); n->removeType = OBJECT_OPCLASS; n->behavior = $9; n->missing_ok = true; @@ -5387,8 +5383,7 @@ DropOpFamilyStmt: DROP OPERATOR FAMILY any_name USING access_method opt_drop_behavior { DropStmt *n = makeNode(DropStmt); - n->objects = list_make1($4); - n->arguments = list_make1(list_make1(makeString($6))); + n->objects = list_make1(lcons(makeString($6), $4)); n->removeType = OBJECT_OPFAMILY; n->behavior = $7; n->missing_ok = false; @@ -5398,8 +5393,7 @@ DropOpFamilyStmt: | DROP OPERATOR FAMILY IF_P EXISTS any_name USING access_method opt_drop_behavior { DropStmt *n = makeNode(DropStmt); - n->objects = list_make1($6); - n->arguments = list_make1(list_make1(makeString($8))); + n->objects = list_make1(lcons(makeString($8), $6)); n->removeType = OBJECT_OPFAMILY; n->behavior = $9; n->missing_ok = true; @@ -5741,8 +5735,7 @@ CommentStmt: { CommentStmt *n = makeNode(CommentStmt); n->objtype = OBJECT_OPCLASS; - n->objname = $5; - n->objargs = list_make1(makeString($7)); + n->objname = lcons(makeString($7), $5); n->comment = $9; $$ = (Node *) n; } @@ -5750,8 +5743,8 @@ CommentStmt: { CommentStmt *n = makeNode(CommentStmt); n->objtype = OBJECT_OPFAMILY; - n->objname = $5; - n->objargs = list_make1(makeString($7)); + n->objname = lcons(makeString($7), $5); + n->objargs = NIL; n->comment = $9; $$ = (Node *) n; } @@ -7476,8 +7469,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name { RenameStmt *n = makeNode(RenameStmt); n->renameType = OBJECT_OPCLASS; - n->object = $4; - n->objarg = list_make1(makeString($6)); + n->object = lcons(makeString($6), $4); n->newname = $9; n->missing_ok = false; $$ = (Node *)n; @@ -7486,8 +7478,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name { RenameStmt *n = makeNode(RenameStmt); n->renameType = OBJECT_OPFAMILY; - n->object = $4; - n->objarg = list_make1(makeString($6)); + n->object = lcons(makeString($6), $4); n->newname = $9; n->missing_ok = false; $$ = (Node *)n; @@ -7924,8 +7915,7 @@ AlterObjectSchemaStmt: { AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); n->objectType = OBJECT_OPCLASS; - n->object = $4; - n->objarg = list_make1(makeString($6)); + n->object = lcons(makeString($6), $4); n->newschema = $9; n->missing_ok = false; $$ = (Node *)n; @@ -7934,8 +7924,7 @@ AlterObjectSchemaStmt: { AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); n->objectType = OBJECT_OPFAMILY; - n->object = $4; - n->objarg = list_make1(makeString($6)); + n->object = lcons(makeString($6), $4); n->newschema = $9; n->missing_ok = false; $$ = (Node *)n; @@ -8162,8 +8151,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleSpec { AlterOwnerStmt *n = makeNode(AlterOwnerStmt); n->objectType = OBJECT_OPCLASS; - n->object = $4; - n->objarg = list_make1(makeString($6)); + n->object = lcons(makeString($6), $4); n->newowner = $9; $$ = (Node *)n; } @@ -8171,8 +8159,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleSpec { AlterOwnerStmt *n = makeNode(AlterOwnerStmt); n->objectType = OBJECT_OPFAMILY; - n->object = $4; - n->objarg = list_make1(makeString($6)); + n->object = lcons(makeString($6), $4); n->newowner = $9; $$ = (Node *)n; } |