Stephen Frost wrote:

> I thought the rest of it looked alright.  I agree it's a bit odd how the
> opfamily is handled but I agree with your assessment that there's not
> much better we can do with this object representation.

Actually, on second thought I revisited this and changed the
representation for opfamilies and opclasses: instead of putting the AM
name in objargs, we can put it as the first element of objname instead.
That way, objargs is unused for opfamilies and opclasses, and we're free
to use it for the type arguments in amops and amprocs.  This makes the
lists consistent for the four cases: in objname, amname first, then
qualified opclass/opfamily name.  For amop/amproc, the member number
follows.  Objargs is unused in opclass/opfamily, and it's a two-element
list of types in amop/amproc.

The attached patch changes the grammar to comply with the above, and
adds the necessary get_object_address and getObjectIdentityParts support
code for amop/amproc objects.

The only thing a bit unusual is that in does_not_exist_skipping() we
need to do an list_copy_tail() to strip out the amname before reporting
the "skipping" message, for DROP OPERATOR CLASS/FAMILY IF NOT EXISTS.
I don't think this is a problem.  In return, the code to deconstruct
amop and amproc addresses is more sensible.

-- 
Álvaro Herrera                http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
>From 35336c997b8be18d890a3a8bdf2822f757f70faf 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] Support opfamily members in get_object_address

In the spirit of 890192e99af and 4464303405f, have get_object_address
understand pg_amop and pg_amproc objects.  There is no way to refer to
such objects directly in the grammar, but in event triggers and
pg_get_object_address it becomes possible to become involved with them.

Reviewed by: Stephen Frost
---
 src/backend/catalog/objectaddress.c          | 234 +++++++++++++++++++++------
 src/backend/commands/dropcmds.c              |  24 ++-
 src/backend/commands/event_trigger.c         |   2 +
 src/backend/parser/gram.y                    |  43 ++---
 src/include/nodes/parsenodes.h               |   2 +
 src/test/regress/expected/object_address.out |  60 ++++---
 src/test/regress/sql/object_address.sql      |  16 +-
 7 files changed, 264 insertions(+), 117 deletions(-)

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 142bc68..46ea09a 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 e5185ba..a1b0d4d 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 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/backend/parser/gram.y b/src/backend/parser/gram.y
index cf0d317..b5804f4 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 = list_make1(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;
 				}
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 38ed661..5de1b75 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1232,6 +1232,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 3bcbcd8..365dcca 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
@@ -197,18 +195,18 @@ WARNING:  error for operator,{addr_nsp,zwei},{}: argument list length must be ex
 WARNING:  error for operator,{addr_nsp,zwei},{integer}: argument list length must be exactly 2
 WARNING:  error for operator,{eins,zwei,drei},{}: argument list length must be exactly 2
 WARNING:  error for operator,{eins,zwei,drei},{integer}: argument list length must be exactly 2
-WARNING:  error for operator class,{eins},{}: argument list length must be exactly 1
-WARNING:  error for operator class,{eins},{integer}: access method "integer" does not exist
-WARNING:  error for operator class,{addr_nsp,zwei},{}: argument list length must be exactly 1
-WARNING:  error for operator class,{addr_nsp,zwei},{integer}: access method "integer" does not exist
-WARNING:  error for operator class,{eins,zwei,drei},{}: argument list length must be exactly 1
-WARNING:  error for operator class,{eins,zwei,drei},{integer}: access method "integer" does not exist
-WARNING:  error for operator family,{eins},{}: argument list length must be exactly 1
-WARNING:  error for operator family,{eins},{integer}: access method "integer" does not exist
-WARNING:  error for operator family,{addr_nsp,zwei},{}: argument list length must be exactly 1
-WARNING:  error for operator family,{addr_nsp,zwei},{integer}: access method "integer" does not exist
-WARNING:  error for operator family,{eins,zwei,drei},{}: argument list length must be exactly 1
-WARNING:  error for operator family,{eins,zwei,drei},{integer}: access method "integer" does not exist
+WARNING:  error for operator class,{eins},{}: name list length must be at least 2
+WARNING:  error for operator class,{eins},{integer}: name list length must be at least 2
+WARNING:  error for operator class,{addr_nsp,zwei},{}: access method "addr_nsp" does not exist
+WARNING:  error for operator class,{addr_nsp,zwei},{integer}: access method "addr_nsp" does not exist
+WARNING:  error for operator class,{eins,zwei,drei},{}: access method "eins" does not exist
+WARNING:  error for operator class,{eins,zwei,drei},{integer}: access method "eins" does not exist
+WARNING:  error for operator family,{eins},{}: name list length must be at least 2
+WARNING:  error for operator family,{eins},{integer}: name list length must be at least 2
+WARNING:  error for operator family,{addr_nsp,zwei},{}: access method "addr_nsp" does not exist
+WARNING:  error for operator family,{addr_nsp,zwei},{integer}: access method "addr_nsp" does not exist
+WARNING:  error for operator family,{eins,zwei,drei},{}: access method "eins" does not exist
+WARNING:  error for operator family,{eins,zwei,drei},{integer}: access method "eins" does not exist
 WARNING:  error for rule,{eins},{}: rule "eins" does not exist
 WARNING:  error for rule,{eins},{integer}: rule "eins" does not exist
 WARNING:  error for rule,{addr_nsp,zwei},{}: relation "addr_nsp" does not exist
@@ -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}: unrecognized default ACL object type i
 WARNING:  error for default acl,{eins,zwei,drei},{}: argument list length must be exactly 1
 WARNING:  error for default acl,{eins,zwei,drei},{integer}: unrecognized default ACL object type i
+WARNING:  error for operator of access method,{eins},{}: name list length must be at least 3
+WARNING:  error for operator of access method,{eins},{integer}: name list length must be at least 3
+WARNING:  error for operator of access method,{addr_nsp,zwei},{}: name list length must be at least 3
+WARNING:  error for operator of access method,{addr_nsp,zwei},{integer}: name list length must be at least 3
+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 3
+WARNING:  error for function of access method,{eins},{integer}: name list length must be at least 3
+WARNING:  error for function of access method,{addr_nsp,zwei},{}: name list length must be at least 3
+WARNING:  error for function of access method,{addr_nsp,zwei},{integer}: name list length must be at least 3
+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
@@ -332,10 +342,10 @@ WITH objects (type, name, args) AS (VALUES
 				('language', '{plpgsql}', '{}'),
 				-- large object
 				('operator', '{+}', '{int4, int4}'),
-				('operator class', '{int4_ops}', '{btree}'),
-				('operator family', '{integer_ops}', '{btree}'),
-				-- operator of access method
-				-- function of access method
+				('operator class', '{btree, int4_ops}', '{}'),
+				('operator family', '{btree, integer_ops}', '{}'),
+				('operator of access method', '{btree,integer_ops,1}', '{integer,integer}'),
+				('function of access method', '{btree,integer_ops,2}', '{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 a49f03f..9cf8097 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
@@ -141,10 +141,10 @@ WITH objects (type, name, args) AS (VALUES
 				('language', '{plpgsql}', '{}'),
 				-- large object
 				('operator', '{+}', '{int4, int4}'),
-				('operator class', '{int4_ops}', '{btree}'),
-				('operator family', '{integer_ops}', '{btree}'),
-				-- operator of access method
-				-- function of access method
+				('operator class', '{btree, int4_ops}', '{}'),
+				('operator family', '{btree, integer_ops}', '{}'),
+				('operator of access method', '{btree,integer_ops,1}', '{integer,integer}'),
+				('function of access method', '{btree,integer_ops,2}', '{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

Reply via email to