1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-13 16:22:44 +03:00

Support opfamily members in get_object_address

In the spirit of 890192e99a and 4464303405: 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
This commit is contained in:
Alvaro Herrera
2015-03-16 12:06:34 -03:00
parent 8d1f239003
commit a61fd5334e
7 changed files with 264 additions and 117 deletions

View File

@@ -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)
{
@@ -1384,6 +1390,114 @@ get_object_address_opcf(ObjectType objtype,
return address;
}
/*
* 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.
*/
@@ -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);

View File

@@ -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:

View File

@@ -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:

View File

@@ -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;
}