Here's a patch implementing the proposed idea.  This is used in the
Bidirectional Replication stuff by Simon/Andres; it works well.


One thing of note is that I added output flags for "normal" and
"original", which mostly come from performDeletion flags.  This let one
select only such objects when trying to replicate a drop; otherwise,
we'd add RI triggers to the set to drop remotely, which doesn't work
because their names have OIDs embedded, and in the remote system those
are different.

One curious thing is that I had to add a hack that if an object has a
"reverse" flag in the ObjectAddresses array, also set the "normal"
output flag.  (Another possibility would have been to add a "reverse"
output flag, but there doesn't seem to be a use for that --- it seems to
expose internals unnecessarily.)

-- 
Álvaro Herrera                http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 17538,17543 **** FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
--- 17538,17556 ----
          <entry>Object sub-id (e.g. attribute number for columns)</entry>
         </row>
         <row>
+         <entry><literal>original</literal></entry>
+         <entry><type>bool</type></entry>
+         <entry>Flag used to identify the root object of the deletion</entry>
+        </row>
+        <row>
+         <entry></literal>normal</literal></entry>
+         <entry><type>bool</type></entry>
+         <entry>
+          Flag indicating that there's a normal dependency relationship
+          in the dependency graph leading to this object
+         </entry>
+        </row>
+        <row>
          <entry><literal>object_type</literal></entry>
          <entry><type>text</type></entry>
          <entry>Type of the object</entry>
***************
*** 17567,17572 **** FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
--- 17580,17601 ----
           identifier present in the identity is quoted if necessary.
          </entry>
         </row>
+        <row>
+         <entry><literal>address_names</literal></entry>
+         <entry><type>text[]</type></entry>
+         <entry>
+          An array that, together with <literal>address_args</literal>,
+          can be used by the C-language function getObjectAddress() to
+          recreate the object address in a remote server containing a similar object.
+         <entry>
+        </row>
+        <row>
+         <entry><literal>address_args</literal></entry>
+         <entry><type>text[]</type></entry>
+         <entry>
+          See <literal>address_names</literal> above.
+         </entry>
+        </row>
        </tbody>
       </tgroup>
      </informaltable>
*** a/src/backend/catalog/dependency.c
--- b/src/backend/catalog/dependency.c
***************
*** 203,218 **** deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel,
  	/*
  	 * Keep track of objects for event triggers, if necessary.
  	 */
! 	if (trackDroppedObjectsNeeded())
  	{
  		for (i = 0; i < targetObjects->numrefs; i++)
  		{
! 			ObjectAddress *thisobj = targetObjects->refs + i;
! 
! 			if ((!(flags & PERFORM_DELETION_INTERNAL)) &&
! 				EventTriggerSupportsObjectClass(getObjectClass(thisobj)))
  			{
! 				EventTriggerSQLDropAddObject(thisobj);
  			}
  		}
  	}
--- 203,227 ----
  	/*
  	 * Keep track of objects for event triggers, if necessary.
  	 */
! 	if (trackDroppedObjectsNeeded() && !(flags & PERFORM_DELETION_INTERNAL))
  	{
  		for (i = 0; i < targetObjects->numrefs; i++)
  		{
! 			const ObjectAddress *thisobj = &targetObjects->refs[i];
! 			const ObjectAddressExtra *extra = &targetObjects->extras[i];
! 			bool	original = false;
! 			bool	normal = false;
! 
! 			if (extra->flags & DEPFLAG_ORIGINAL)
! 				original = true;
! 			if (extra->flags & DEPFLAG_NORMAL)
! 				normal = true;
! 			if (extra->flags & DEPFLAG_REVERSE)
! 				normal = true;
! 
! 			if (EventTriggerSupportsObjectClass(getObjectClass(thisobj)))
  			{
! 				EventTriggerSQLDropAddObject(thisobj, original, normal);
  			}
  		}
  	}
*** a/src/backend/catalog/objectaddress.c
--- b/src/backend/catalog/objectaddress.c
***************
*** 417,422 **** static const ObjectPropertyType ObjectProperty[] =
--- 417,513 ----
  	}
  };
  
+ /*
+  * This struct maps the object types as returned by getObjectTypeDescription
+  * into ObjType enum values.  Note that some enum values can be obtained by
+  * different names, and that some string object types do not have corresponding
+  * values in the enum.  The user of this map must be careful to test for
+  * invalid values being returned.
+  *
+  * This follows the order of getObjectTypeDescription.
+  */
+ static const struct object_type_map
+ {
+ 	const char *tm_name;
+ 	ObjectType	tm_type;
+ }
+ ObjectTypeMap[] =
+ {
+ 	/* OCLASS_CLASS */
+ 	{ "table", OBJECT_TABLE },
+ 	{ "index", OBJECT_INDEX },
+ 	{ "sequence", OBJECT_SEQUENCE },
+ 	{ "toast table", -1 },		/* unmapped */
+ 	{ "view", OBJECT_VIEW },
+ 	{ "materialized view", OBJECT_MATVIEW },
+ 	{ "composite type", OBJECT_COMPOSITE },
+ 	{ "foreign table", OBJECT_FOREIGN_TABLE },
+ 	{ "table column", OBJECT_COLUMN },
+ 	/* OCLASS_PROC */
+ 	{ "aggregate", OBJECT_AGGREGATE },
+ 	{ "function", OBJECT_FUNCTION },
+ 	/* OCLASS_TYPE */
+ 	{ "type", OBJECT_TYPE },
+ 	/* OCLASS_CAST */
+ 	{ "cast", OBJECT_CAST },
+ 	/* OCLASS_COLLATION */
+ 	{ "collation", OBJECT_COLLATION },
+ 	/* OCLASS_CONSTRAINT */
+ 	{ "table constraint", OBJECT_CONSTRAINT },
+ 	{ "domain constraint", OBJECT_CONSTRAINT },
+ 	/* OCLASS_CONVERSION */
+ 	{ "conversion", OBJECT_CONVERSION },
+ 	/* OCLASS_DEFAULT */
+ 	{ "default value", OBJECT_DEFAULT },
+ 	/* OCLASS_LANGUAGE */
+ 	{ "language", OBJECT_LANGUAGE },
+ 	/* OCLASS_LARGEOBJECT */
+ 	{ "large object", OBJECT_LARGEOBJECT },
+ 	/* OCLASS_OPERATOR */
+ 	{ "operator", OBJECT_OPERATOR },
+ 	/* OCLASS_OPCLASS */
+ 	{ "operator class", OBJECT_OPCLASS },
+ 	/* OCLASS_OPFAMILY */
+ 	{ "operator family", OBJECT_OPFAMILY },
+ 	/* OCLASS_AMOP */
+ 	{ "operator of access method", -1 },	/* unmapped */
+ 	/* OCLASS_AMPROC */
+ 	{ "function of access method", -1 },	/* unmapped */
+ 	/* OCLASS_REWRITE */
+ 	{ "rule", OBJECT_RULE },
+ 	/* OCLASS_TRIGGER */
+ 	{ "trigger", OBJECT_TRIGGER },
+ 	/* OCLASS_SCHEMA */
+ 	{ "schema", OBJECT_SCHEMA },
+ 	/* OCLASS_TSPARSER */
+ 	{ "text search parser", OBJECT_TSPARSER },
+ 	/* OCLASS_TSDICT */
+ 	{ "text search dictionary", OBJECT_TSDICTIONARY },
+ 	/* OCLASS_TSTEMPLATE */
+ 	{ "text search template", OBJECT_TSTEMPLATE },
+ 	/* OCLASS_TSCONFIG */
+ 	{ "text search configuration", OBJECT_TSCONFIGURATION },
+ 	/* OCLASS_ROLE */
+ 	{ "role", OBJECT_ROLE },
+ 	/* OCLASS_DATABASE */
+ 	{ "database", OBJECT_DATABASE },
+ 	/* OCLASS_TBLSPACE */
+ 	{ "tablespace", OBJECT_TABLESPACE },
+ 	/* OCLASS_FDW */
+ 	{ "foreign-data wrapper", OBJECT_FDW },
+ 	/* OCLASS_FOREIGN_SERVER */
+ 	{ "server", OBJECT_FOREIGN_SERVER },
+ 	/* OCLASS_USER_MAPPING */
+ 	{ "user mapping", OBJECT_USER_MAPPING },
+ 	/* OCLASS_DEFACL */
+ 	{ "default acl", -1 },			/* FIXME */
+ 	/* OCLASS_EXTENSION */
+ 	{ "extension", OBJECT_EXTENSION },
+ 	/* OCLASS_EVENT_TRIGGER */
+ 	{ "event trigger", OBJECT_EVENT_TRIGGER }
+ };
+ 
+ 
  static ObjectAddress get_object_address_unqualified(ObjectType objtype,
  							   List *qualname, bool missing_ok);
  static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
***************
*** 439,446 **** 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);
! static void getRelationIdentity(StringInfo buffer, Oid relid);
  
  /*
   * Translate an object name and arguments (as passed by the parser) to an
--- 530,538 ----
  						   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 getRelationIdentity(StringInfo buffer, Oid relid, List **objname);
  
  /*
   * Translate an object name and arguments (as passed by the parser) to an
***************
*** 1347,1352 **** get_object_namespace(const ObjectAddress *address)
--- 1439,1472 ----
  }
  
  /*
+  * Return ObjectType for the given object type as given by
+  * getObjectTypeDescription; if no valid ObjectType code exists, but it's a
+  * possible output type from getObjectTypeDescription, return -1.
+  * Otherwise, an error is thrown.
+  */
+ int
+ unstringify_objtype(const char *objtype)
+ {
+ 	ObjectType	type;
+ 	int			i;
+ 
+ 	for (i = 0; i < lengthof(ObjectTypeMap); i++)
+ 	{
+ 		if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0)
+ 		{
+ 			type = ObjectTypeMap[i].tm_type;
+ 			break;
+ 		}
+ 	}
+ 	if (i >= lengthof(ObjectTypeMap))
+ 		ereport(ERROR,
+ 			   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ 				errmsg("unrecognized object type \"%s\"", objtype)));
+ 
+ 	return type;
+ }
+ 
+ /*
   * Interfaces to reference fields of ObjectPropertyType
   */
  Oid
***************
*** 2442,2447 **** pg_identify_object(PG_FUNCTION_ARGS)
--- 2562,2569 ----
  /*
   * Return a palloc'ed string that describes the type of object that the
   * passed address is for.
+  *
+  * Keep ObjectTypeMap in sync with this.
   */
  char *
  getObjectTypeDescription(const ObjectAddress *object)
***************
*** 2689,2695 **** getProcedureTypeDescription(StringInfo buffer, Oid procid)
  }
  
  /*
!  * Return a palloc'ed string that identifies an object.
   *
   * This is for machine consumption, so it's not translated.  All elements are
   * schema-qualified when appropriate.
--- 2811,2817 ----
  }
  
  /*
!  * Obtain a given object's identity, as a palloc'ed string.
   *
   * This is for machine consumption, so it's not translated.  All elements are
   * schema-qualified when appropriate.
***************
*** 2697,2710 **** getProcedureTypeDescription(StringInfo buffer, Oid procid)
  char *
  getObjectIdentity(const ObjectAddress *object)
  {
  	StringInfoData buffer;
  
  	initStringInfo(&buffer);
  
  	switch (getObjectClass(object))
  	{
  		case OCLASS_CLASS:
! 			getRelationIdentity(&buffer, object->objectId);
  			if (object->objectSubId != 0)
  			{
  				char	   *attr;
--- 2819,2855 ----
  char *
  getObjectIdentity(const ObjectAddress *object)
  {
+ 	return getObjectIdentityParts(object, NULL, NULL);
+ }
+ 
+ /*
+  * As above, but more detailed.
+  *
+  * There are two sets of return values: the identity itself as a palloc'd
+  * string is returned.  objname and objargs, if not NULL, are output parameters
+  * that receive lists of strings that are useful to give back to
+  * get_object_address() to reconstruct the ObjectAddress.
+  */
+ char *
+ getObjectIdentityParts(const ObjectAddress *object,
+ 					   List **objname, List **objargs)
+ {
  	StringInfoData buffer;
  
  	initStringInfo(&buffer);
  
+ 	/*
+ 	 * Make sure that both objname and objargs were passed, or none was.
+ 	 * Initialize objargs to empty list, which is the most common case.
+ 	 */
+ 	Assert(PointerIsValid(objname) == PointerIsValid(objargs));
+ 	if (objargs)
+ 		*objargs = NIL;
+ 
  	switch (getObjectClass(object))
  	{
  		case OCLASS_CLASS:
! 			getRelationIdentity(&buffer, object->objectId, objname);
  			if (object->objectSubId != 0)
  			{
  				char	   *attr;
***************
*** 2712,2728 **** getObjectIdentity(const ObjectAddress *object)
  				attr = get_relid_attribute_name(object->objectId,
  												object->objectSubId);
  				appendStringInfo(&buffer, ".%s", quote_identifier(attr));
  			}
  			break;
  
  		case OCLASS_PROC:
  			appendStringInfoString(&buffer,
  							   format_procedure_qualified(object->objectId));
  			break;
  
  		case OCLASS_TYPE:
! 			appendStringInfoString(&buffer,
! 								 format_type_be_qualified(object->objectId));
  			break;
  
  		case OCLASS_CAST:
--- 2857,2883 ----
  				attr = get_relid_attribute_name(object->objectId,
  												object->objectSubId);
  				appendStringInfo(&buffer, ".%s", quote_identifier(attr));
+ 				if (objname)
+ 					*objname = lappend(*objname, attr);
  			}
  			break;
  
  		case OCLASS_PROC:
  			appendStringInfoString(&buffer,
  							   format_procedure_qualified(object->objectId));
+ 			if (objname)
+ 				format_procedure_parts(object->objectId, objname, objargs);
  			break;
  
  		case OCLASS_TYPE:
! 			{
! 				char *typeout;
! 
! 				typeout = format_type_be_qualified(object->objectId);
! 				appendStringInfoString(&buffer, typeout);
! 				if (objname)
! 					*objname = list_make1(typeout);
! 			}
  			break;
  
  		case OCLASS_CAST:
***************
*** 2745,2750 **** getObjectIdentity(const ObjectAddress *object)
--- 2900,2909 ----
  							  format_type_be_qualified(castForm->castsource),
  							 format_type_be_qualified(castForm->casttarget));
  
+ 				if (objname)
+ 					*objname = list_make2(format_type_be_qualified(castForm->castsource),
+ 										  format_type_be_qualified(castForm->casttarget));
+ 
  				heap_close(castRel, AccessShareLock);
  				break;
  			}
***************
*** 2765,2770 **** getObjectIdentity(const ObjectAddress *object)
--- 2924,2931 ----
  				appendStringInfoString(&buffer,
  									   quote_qualified_identifier(schema,
  												   NameStr(coll->collname)));
+ 				if (objname)
+ 					*objname = list_make2(schema, NameStr(coll->collname));
  				ReleaseSysCache(collTup);
  				break;
  			}
***************
*** 2785,2791 **** getObjectIdentity(const ObjectAddress *object)
  				{
  					appendStringInfo(&buffer, "%s on ",
  									 quote_identifier(NameStr(con->conname)));
! 					getRelationIdentity(&buffer, con->conrelid);
  				}
  				else
  				{
--- 2946,2954 ----
  				{
  					appendStringInfo(&buffer, "%s on ",
  									 quote_identifier(NameStr(con->conname)));
! 					getRelationIdentity(&buffer, con->conrelid, objname);
! 					if (objname)
! 						*objname = lappend(*objname, pstrdup(NameStr(con->conname)));
  				}
  				else
  				{
***************
*** 2798,2803 **** getObjectIdentity(const ObjectAddress *object)
--- 2961,2968 ----
  					appendStringInfo(&buffer, "%s on %s",
  									 quote_identifier(NameStr(con->conname)),
  									 getObjectIdentity(&domain));
+ 
+ 					/* FIXME missing objname/objargs */
  				}
  
  				ReleaseSysCache(conTup);
***************
*** 2817,2822 **** getObjectIdentity(const ObjectAddress *object)
--- 2982,2989 ----
  				conForm = (Form_pg_conversion) GETSTRUCT(conTup);
  				appendStringInfoString(&buffer,
  								quote_identifier(NameStr(conForm->conname)));
+ 				if (objname)
+ 					*objname = list_make1(pstrdup(NameStr(conForm->conname)));
  				ReleaseSysCache(conTup);
  				break;
  			}
***************
*** 2856,2861 **** getObjectIdentity(const ObjectAddress *object)
--- 3023,3030 ----
  				appendStringInfo(&buffer, "for %s",
  								 getObjectIdentity(&colobject));
  
+ 				/* XXX no objname/objargs here */
+ 
  				systable_endscan(adscan);
  				heap_close(attrdefDesc, AccessShareLock);
  				break;
***************
*** 2874,2890 **** getObjectIdentity(const ObjectAddress *object)
--- 3043,3065 ----
  				langForm = (Form_pg_language) GETSTRUCT(langTup);
  				appendStringInfoString(&buffer,
  							   quote_identifier(NameStr(langForm->lanname)));
+ 				if (objname)
+ 					*objname = list_make1(pstrdup(NameStr(langForm->lanname)));
  				ReleaseSysCache(langTup);
  				break;
  			}
  		case OCLASS_LARGEOBJECT:
  			appendStringInfo(&buffer, "%u",
  							 object->objectId);
+ 			if (objname)
+ 				*objname = list_make1(psprintf("%u", object->objectId));
  			break;
  
  		case OCLASS_OPERATOR:
  			appendStringInfoString(&buffer,
  								format_operator_qualified(object->objectId));
+ 			if (objname)
+ 				format_operator_parts(object->objectId, objname, objargs);
  			break;
  
  		case OCLASS_OPCLASS:
***************
*** 2915,2928 **** getObjectIdentity(const ObjectAddress *object)
  												 NameStr(opcForm->opcname)));
  				appendStringInfo(&buffer, " for %s",
  								 quote_identifier(NameStr(amForm->amname)));
! 
  				ReleaseSysCache(amTup);
  				ReleaseSysCache(opcTup);
  				break;
  			}
  
  		case OCLASS_OPFAMILY:
! 			getOpFamilyIdentity(&buffer, object->objectId);
  			break;
  
  		case OCLASS_AMOP:
--- 3090,3108 ----
  												 NameStr(opcForm->opcname)));
  				appendStringInfo(&buffer, " for %s",
  								 quote_identifier(NameStr(amForm->amname)));
! 				if (objname)
! 				{
! 					*objname = list_make2(pstrdup(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);
  			break;
  
  		case OCLASS_AMOP:
***************
*** 2934,2939 **** getObjectIdentity(const ObjectAddress *object)
--- 3114,3123 ----
  				Form_pg_amop amopForm;
  				StringInfoData opfam;
  
+ 				/* no objname support here */
+ 				if (objname)
+ 					*objname = NIL;
+ 
  				amopDesc = heap_open(AccessMethodOperatorRelationId,
  									 AccessShareLock);
  
***************
*** 2954,2960 **** getObjectIdentity(const ObjectAddress *object)
  				amopForm = (Form_pg_amop) GETSTRUCT(tup);
  
  				initStringInfo(&opfam);
! 				getOpFamilyIdentity(&opfam, amopForm->amopfamily);
  
  				appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
  								 amopForm->amopstrategy,
--- 3138,3144 ----
  				amopForm = (Form_pg_amop) GETSTRUCT(tup);
  
  				initStringInfo(&opfam);
! 				getOpFamilyIdentity(&opfam, amopForm->amopfamily, NULL, NULL);
  
  				appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
  								 amopForm->amopstrategy,
***************
*** 2978,2983 **** getObjectIdentity(const ObjectAddress *object)
--- 3162,3171 ----
  				Form_pg_amproc amprocForm;
  				StringInfoData opfam;
  
+ 				/* no objname support here */
+ 				if (objname)
+ 					*objname = NIL;
+ 
  				amprocDesc = heap_open(AccessMethodProcedureRelationId,
  									   AccessShareLock);
  
***************
*** 2998,3004 **** getObjectIdentity(const ObjectAddress *object)
  				amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
  
  				initStringInfo(&opfam);
! 				getOpFamilyIdentity(&opfam, amprocForm->amprocfamily);
  
  				appendStringInfo(&buffer, "function %d (%s, %s) of %s",
  								 amprocForm->amprocnum,
--- 3186,3192 ----
  				amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
  
  				initStringInfo(&opfam);
! 				getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, NULL, NULL);
  
  				appendStringInfo(&buffer, "function %d (%s, %s) of %s",
  								 amprocForm->amprocnum,
***************
*** 3031,3037 **** getObjectIdentity(const ObjectAddress *object)
  
  				appendStringInfo(&buffer, "%s on ",
  								 quote_identifier(NameStr(rule->rulename)));
! 				getRelationIdentity(&buffer, rule->ev_class);
  
  				heap_close(ruleDesc, AccessShareLock);
  				break;
--- 3219,3227 ----
  
  				appendStringInfo(&buffer, "%s on ",
  								 quote_identifier(NameStr(rule->rulename)));
! 				getRelationIdentity(&buffer, rule->ev_class, objname);
! 				if (objname)
! 					*objname = lappend(*objname, NameStr(rule->rulename));
  
  				heap_close(ruleDesc, AccessShareLock);
  				break;
***************
*** 3055,3061 **** getObjectIdentity(const ObjectAddress *object)
  
  				appendStringInfo(&buffer, "%s on ",
  								 quote_identifier(NameStr(trig->tgname)));
! 				getRelationIdentity(&buffer, trig->tgrelid);
  
  				heap_close(trigDesc, AccessShareLock);
  				break;
--- 3245,3253 ----
  
  				appendStringInfo(&buffer, "%s on ",
  								 quote_identifier(NameStr(trig->tgname)));
! 				getRelationIdentity(&buffer, trig->tgrelid, objname);
! 				if (objname)
! 					*objname = lappend(*objname, NameStr(trig->tgname));
  
  				heap_close(trigDesc, AccessShareLock);
  				break;
***************
*** 3071,3076 **** getObjectIdentity(const ObjectAddress *object)
--- 3263,3270 ----
  						 object->objectId);
  				appendStringInfoString(&buffer,
  									   quote_identifier(nspname));
+ 				if (objname)
+ 					*objname = list_make1(nspname);
  				break;
  			}
  
***************
*** 3090,3095 **** getObjectIdentity(const ObjectAddress *object)
--- 3284,3292 ----
  				appendStringInfoString(&buffer,
  									   quote_qualified_identifier(schema,
  											  NameStr(formParser->prsname)));
+ 				if (objname)
+ 					*objname = list_make2(schema,
+ 										  pstrdup(NameStr(formParser->prsname)));
  				ReleaseSysCache(tup);
  				break;
  			}
***************
*** 3110,3115 **** getObjectIdentity(const ObjectAddress *object)
--- 3307,3315 ----
  				appendStringInfoString(&buffer,
  									   quote_qualified_identifier(schema,
  											   NameStr(formDict->dictname)));
+ 				if (objname)
+ 					*objname = list_make2(schema,
+ 										  pstrdup(NameStr(formDict->dictname)));
  				ReleaseSysCache(tup);
  				break;
  			}
***************
*** 3130,3136 **** getObjectIdentity(const ObjectAddress *object)
  				appendStringInfoString(&buffer,
  									   quote_qualified_identifier(schema,
  											   NameStr(formTmpl->tmplname)));
! 				pfree(schema);
  				ReleaseSysCache(tup);
  				break;
  			}
--- 3330,3338 ----
  				appendStringInfoString(&buffer,
  									   quote_qualified_identifier(schema,
  											   NameStr(formTmpl->tmplname)));
! 				if (objname)
! 					*objname = list_make2(schema,
! 										  pstrdup(NameStr(formTmpl->tmplname)));
  				ReleaseSysCache(tup);
  				break;
  			}
***************
*** 3151,3156 **** getObjectIdentity(const ObjectAddress *object)
--- 3353,3361 ----
  				appendStringInfoString(&buffer,
  									   quote_qualified_identifier(schema,
  												 NameStr(formCfg->cfgname)));
+ 				if (objname)
+ 					*objname = list_make2(schema,
+ 										  pstrdup(NameStr(formCfg->cfgname)));
  				ReleaseSysCache(tup);
  				break;
  			}
***************
*** 3159,3164 **** getObjectIdentity(const ObjectAddress *object)
--- 3364,3372 ----
  			{
  				char	   *username;
  
+ 				/* no objname support here */
+ 				Assert(objname == NULL);
+ 
  				username = GetUserNameFromId(object->objectId);
  				appendStringInfoString(&buffer,
  									   quote_identifier(username));
***************
*** 3169,3174 **** getObjectIdentity(const ObjectAddress *object)
--- 3377,3385 ----
  			{
  				char	   *datname;
  
+ 				/* no objname support here */
+ 				Assert(objname == NULL);
+ 
  				datname = get_database_name(object->objectId);
  				if (!datname)
  					elog(ERROR, "cache lookup failed for database %u",
***************
*** 3182,3187 **** getObjectIdentity(const ObjectAddress *object)
--- 3393,3401 ----
  			{
  				char	   *tblspace;
  
+ 				/* no objname support here */
+ 				Assert(objname == NULL);
+ 
  				tblspace = get_tablespace_name(object->objectId);
  				if (!tblspace)
  					elog(ERROR, "cache lookup failed for tablespace %u",
***************
*** 3197,3202 **** getObjectIdentity(const ObjectAddress *object)
--- 3411,3418 ----
  
  				fdw = GetForeignDataWrapper(object->objectId);
  				appendStringInfoString(&buffer, quote_identifier(fdw->fdwname));
+ 				if (objname)
+ 					*objname = list_make1(pstrdup(fdw->fdwname));
  				break;
  			}
  
***************
*** 3207,3212 **** getObjectIdentity(const ObjectAddress *object)
--- 3423,3430 ----
  				srv = GetForeignServer(object->objectId);
  				appendStringInfoString(&buffer,
  									   quote_identifier(srv->servername));
+ 				if (objname)
+ 					*objname = list_make1(pstrdup(srv->servername));
  				break;
  			}
  
***************
*** 3216,3221 **** getObjectIdentity(const ObjectAddress *object)
--- 3434,3441 ----
  				Oid			useid;
  				const char *usename;
  
+ 				/* XXX get_object_address doesn't seem to support this */
+ 
  				tup = SearchSysCache1(USERMAPPINGOID,
  									  ObjectIdGetDatum(object->objectId));
  				if (!HeapTupleIsValid(tup))
***************
*** 3240,3249 **** getObjectIdentity(const ObjectAddress *object)
  				Relation	defaclrel;
  				ScanKeyData skey[1];
  				SysScanDesc rcscan;
- 
  				HeapTuple	tup;
  				Form_pg_default_acl defacl;
  
  				defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
  
  				ScanKeyInit(&skey[0],
--- 3460,3470 ----
  				Relation	defaclrel;
  				ScanKeyData skey[1];
  				SysScanDesc rcscan;
  				HeapTuple	tup;
  				Form_pg_default_acl defacl;
  
+ 				/* XXX get_object_address doesn't seem to support this */
+ 
  				defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
  
  				ScanKeyInit(&skey[0],
***************
*** 3310,3315 **** getObjectIdentity(const ObjectAddress *object)
--- 3531,3538 ----
  					elog(ERROR, "cache lookup failed for extension %u",
  						 object->objectId);
  				appendStringInfoString(&buffer, quote_identifier(extname));
+ 				if (objname)
+ 					*objname = list_make1(extname);
  				break;
  			}
  
***************
*** 3318,3323 **** getObjectIdentity(const ObjectAddress *object)
--- 3541,3549 ----
  				HeapTuple	tup;
  				Form_pg_event_trigger trigForm;
  
+ 				/* no objname support here */
+ 				Assert(objname == NULL);
+ 
  				tup = SearchSysCache1(EVENTTRIGGEROID,
  									  ObjectIdGetDatum(object->objectId));
  				if (!HeapTupleIsValid(tup))
***************
*** 3342,3348 **** getObjectIdentity(const ObjectAddress *object)
  }
  
  static void
! getOpFamilyIdentity(StringInfo buffer, Oid opfid)
  {
  	HeapTuple	opfTup;
  	Form_pg_opfamily opfForm;
--- 3568,3574 ----
  }
  
  static void
! getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **objname, List **objargs)
  {
  	HeapTuple	opfTup;
  	Form_pg_opfamily opfForm;
***************
*** 3367,3372 **** getOpFamilyIdentity(StringInfo buffer, Oid opfid)
--- 3593,3605 ----
  												NameStr(opfForm->opfname)),
  					 NameStr(amForm->amname));
  
+ 	if (objname)
+ 	{
+ 		*objname = list_make2(pstrdup(schema),
+ 							  pstrdup(NameStr(opfForm->opfname)));
+ 		*objargs = list_make1(pstrdup(NameStr(amForm->amname)));
+ 	}
+ 
  	ReleaseSysCache(amTup);
  	ReleaseSysCache(opfTup);
  }
***************
*** 3376,3382 **** getOpFamilyIdentity(StringInfo buffer, Oid opfid)
   * StringInfo.
   */
  static void
! getRelationIdentity(StringInfo buffer, Oid relid)
  {
  	HeapTuple	relTup;
  	Form_pg_class relForm;
--- 3609,3615 ----
   * StringInfo.
   */
  static void
! getRelationIdentity(StringInfo buffer, Oid relid, List **objname)
  {
  	HeapTuple	relTup;
  	Form_pg_class relForm;
***************
*** 3392,3397 **** getRelationIdentity(StringInfo buffer, Oid relid)
--- 3625,3632 ----
  	appendStringInfoString(buffer,
  						   quote_qualified_identifier(schema,
  												 NameStr(relForm->relname)));
+ 	if (objname)
+ 		*objname = list_make2(schema, pstrdup(NameStr(relForm->relname)));
  
  	ReleaseSysCache(relTup);
  }
*** a/src/backend/commands/event_trigger.c
--- b/src/backend/commands/event_trigger.c
***************
*** 111,116 **** typedef struct SQLDropObject
--- 111,121 ----
  	const char *objname;
  	const char *objidentity;
  	const char *objecttype;
+ 	List	   *addrnames;
+ 	List	   *addrargs;
+ 	ObjectAddress dependee;
+ 	bool		original;
+ 	bool		normal;
  	slist_node	next;
  } SQLDropObject;
  
***************
*** 920,928 **** EventTriggerSupportsObjectType(ObjectType obtype)
--- 925,935 ----
  		case OBJECT_ATTRIBUTE:
  		case OBJECT_CAST:
  		case OBJECT_COLUMN:
+ 		case OBJECT_COMPOSITE:
  		case OBJECT_CONSTRAINT:
  		case OBJECT_COLLATION:
  		case OBJECT_CONVERSION:
+ 		case OBJECT_DEFAULT:
  		case OBJECT_DOMAIN:
  		case OBJECT_EXTENSION:
  		case OBJECT_FDW:
***************
*** 946,951 **** EventTriggerSupportsObjectType(ObjectType obtype)
--- 953,959 ----
  		case OBJECT_TSPARSER:
  		case OBJECT_TSTEMPLATE:
  		case OBJECT_TYPE:
+ 		case OBJECT_USER_MAPPING:
  		case OBJECT_VIEW:
  			return true;
  	}
***************
*** 1102,1108 **** trackDroppedObjectsNeeded(void)
   * Register one object as being dropped by the current command.
   */
  void
! EventTriggerSQLDropAddObject(ObjectAddress *object)
  {
  	SQLDropObject *obj;
  	MemoryContext oldcxt;
--- 1110,1116 ----
   * Register one object as being dropped by the current command.
   */
  void
! EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
  {
  	SQLDropObject *obj;
  	MemoryContext oldcxt;
***************
*** 1121,1126 **** EventTriggerSQLDropAddObject(ObjectAddress *object)
--- 1129,1136 ----
  
  	obj = palloc0(sizeof(SQLDropObject));
  	obj->address = *object;
+ 	obj->original = original;
+ 	obj->normal = normal;
  
  	/*
  	 * Obtain schema names from the object's catalog tuple, if one exists;
***************
*** 1182,1191 **** EventTriggerSQLDropAddObject(ObjectAddress *object)
  		heap_close(catalog, AccessShareLock);
  	}
  
! 	/* object identity */
! 	obj->objidentity = getObjectIdentity(&obj->address);
  
! 	/* and object type, too */
  	obj->objecttype = getObjectTypeDescription(&obj->address);
  
  	slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
--- 1192,1202 ----
  		heap_close(catalog, AccessShareLock);
  	}
  
! 	/* object identity, objname and objargs */
! 	obj->objidentity =
! 		getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs);
  
! 	/* object type */
  	obj->objecttype = getObjectTypeDescription(&obj->address);
  
  	slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
***************
*** 1248,1255 **** pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
  	{
  		SQLDropObject *obj;
  		int			i = 0;
! 		Datum		values[7];
! 		bool		nulls[7];
  
  		obj = slist_container(SQLDropObject, next, iter.cur);
  
--- 1259,1266 ----
  	{
  		SQLDropObject *obj;
  		int			i = 0;
! 		Datum		values[11];
! 		bool		nulls[11];
  
  		obj = slist_container(SQLDropObject, next, iter.cur);
  
***************
*** 1265,1270 **** pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
--- 1276,1287 ----
  		/* objsubid */
  		values[i++] = Int32GetDatum(obj->address.objectSubId);
  
+ 		/* original */
+ 		values[i++] = BoolGetDatum(obj->original);
+ 
+ 		/* normal */
+ 		values[i++] = BoolGetDatum(obj->normal);
+ 
  		/* object_type */
  		values[i++] = CStringGetTextDatum(obj->objecttype);
  
***************
*** 1286,1291 **** pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
--- 1303,1356 ----
  		else
  			nulls[i++] = true;
  
+ 		/* address_names */
+ 		if (obj->addrnames)
+ 		{
+ 			ArrayType *arr;
+ 			Datum	*datums;
+ 			int		j = 0;
+ 			ListCell *cell;
+ 
+ 			datums = palloc(sizeof(text *) * list_length(obj->addrnames));
+ 			foreach(cell, obj->addrnames)
+ 			{
+ 				char   *name = lfirst(cell);
+ 
+ 				datums[j++] = CStringGetTextDatum(name);
+ 			}
+ 
+ 			arr = construct_array(datums, list_length(obj->addrnames),
+ 								  TEXTOID, -1, false, 'i');
+ 
+ 			values[i++] = PointerGetDatum(arr);
+ 		}
+ 		else
+ 			nulls[i++] = true;
+ 
+ 		/* address_args */
+ 		/* FIXME duplicated code block ... */
+ 		if (obj->addrargs)
+ 		{
+ 			ArrayType *arr;
+ 			Datum   *datums;
+ 			int		j = 0;
+ 			ListCell *cell;
+ 
+ 			datums = palloc(sizeof(text *) * list_length(obj->addrargs));
+ 			foreach(cell, obj->addrargs)
+ 			{
+ 				char	*arg = lfirst(cell);
+ 
+ 				datums[j++] = CStringGetTextDatum(arg);
+ 			}
+ 
+ 			arr = construct_array(datums, list_length(obj->addrargs),
+ 								  TEXTOID, -1, false, 'i');
+ 			values[i++] = PointerGetDatum(arr);
+ 		}
+ 		else
+ 			nulls[i++] = true;
+ 
  		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
  	}
  
*** a/src/backend/parser/parse_type.c
--- b/src/backend/parser/parse_type.c
***************
*** 705,717 **** pts_error_callback(void *arg)
  /*
   * Given a string that is supposed to be a SQL-compatible type declaration,
   * such as "int4" or "integer" or "character varying(32)", parse
!  * the string and convert it to a type OID and type modifier.
!  * If missing_ok is true, InvalidOid is returned rather than raising an error
!  * when the type name is not found.
   */
! void
! parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
! 				bool missing_ok)
  {
  	StringInfoData buf;
  	List	   *raw_parsetree_list;
--- 705,715 ----
  /*
   * Given a string that is supposed to be a SQL-compatible type declaration,
   * such as "int4" or "integer" or "character varying(32)", parse
!  * the string and return the result as a TypeName.
!  * If the string cannot be parsed as a type, an error is raised.
   */
! TypeName *
! typeStringToTypeName(const char *str)
  {
  	StringInfoData buf;
  	List	   *raw_parsetree_list;
***************
*** 720,726 **** parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
  	TypeCast   *typecast;
  	TypeName   *typeName;
  	ErrorContextCallback ptserrcontext;
- 	Type		tup;
  
  	/* make sure we give useful error for empty input */
  	if (strspn(str, " \t\n\r\f") == strlen(str))
--- 718,723 ----
***************
*** 779,784 **** parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
--- 776,782 ----
  		typecast->arg == NULL ||
  		!IsA(typecast->arg, A_Const))
  		goto fail;
+ 
  	typeName = typecast->typeName;
  	if (typeName == NULL ||
  		!IsA(typeName, TypeName))
***************
*** 786,791 **** parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
--- 784,814 ----
  	if (typeName->setof)
  		goto fail;
  
+ 	pfree(buf.data);
+ 
+ 	return typeName;
+ 
+ fail:
+ 	ereport(ERROR,
+ 			(errcode(ERRCODE_SYNTAX_ERROR),
+ 			 errmsg("invalid type name \"%s\"", str)));
+ }
+ 
+ /*
+  * Given a string that is supposed to be a SQL-compatible type declaration,
+  * such as "int4" or "integer" or "character varying(32)", parse
+  * the string and convert it to a type OID and type modifier.
+  * If missing_ok is true, InvalidOid is returned rather than raising an error
+  * when the type name is not found.
+  */
+ void
+ parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok)
+ {
+ 	TypeName   *typeName;
+ 	Type		tup;
+ 
+ 	typeName = typeStringToTypeName(str);
+ 
  	tup = LookupTypeName(NULL, typeName, typmod_p, missing_ok);
  	if (tup == NULL)
  	{
***************
*** 808,820 **** parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
  		*typeid_p = HeapTupleGetOid(tup);
  		ReleaseSysCache(tup);
  	}
- 
- 	pfree(buf.data);
- 
- 	return;
- 
- fail:
- 	ereport(ERROR,
- 			(errcode(ERRCODE_SYNTAX_ERROR),
- 			 errmsg("invalid type name \"%s\"", str)));
  }
--- 831,834 ----
*** a/src/backend/utils/adt/regproc.c
--- b/src/backend/utils/adt/regproc.c
***************
*** 439,444 **** format_procedure_internal(Oid procedure_oid, bool force_qualify)
--- 439,479 ----
  }
  
  /*
+  * Output a objname/objargs representation for the procedure with the
+  * given OID.  If it doesn't exist, an error is thrown.
+  *
+  * This can be used to feed get_object_address.
+  */
+ void
+ format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs)
+ {
+ 	HeapTuple	proctup;
+ 	Form_pg_proc procform;
+ 	int			nargs;
+ 	int			i;
+ 
+ 	proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
+ 
+ 	if (!HeapTupleIsValid(proctup))
+ 		elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid);
+ 
+ 	procform = (Form_pg_proc) GETSTRUCT(proctup);
+ 	nargs = procform->pronargs;
+ 
+ 	*objnames = list_make2(get_namespace_name(procform->pronamespace),
+ 						   pstrdup(NameStr(procform->proname)));
+ 	*objargs = NIL;
+ 	for (i = 0; i < nargs; i++)
+ 	{
+ 		Oid		thisargtype = procform->proargtypes.values[i];
+ 
+ 		*objargs = lappend(*objargs, format_type_be_qualified(thisargtype));
+ 	}
+ 
+ 	ReleaseSysCache(proctup);
+ }
+ 
+ /*
   * regprocedureout		- converts proc OID to "pro_name(args)"
   */
  Datum
***************
*** 875,880 **** format_operator_qualified(Oid operator_oid)
--- 910,940 ----
  	return format_operator_internal(operator_oid, true);
  }
  
+ void
+ format_operator_parts(Oid operator_oid, List **objnames, List **objargs)
+ {
+ 	HeapTuple	opertup;
+ 	Form_pg_operator oprForm;
+ 
+ 	opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
+ 	if (!HeapTupleIsValid(opertup))
+ 		elog(ERROR, "cache lookup failed for operator with OID %u",
+ 			 operator_oid);
+ 
+ 	oprForm = (Form_pg_operator) GETSTRUCT(opertup);
+ 	*objnames = list_make2(get_namespace_name(oprForm->oprnamespace),
+ 						   pstrdup(NameStr(oprForm->oprname)));
+ 	*objargs = NIL;
+ 	if (oprForm->oprleft)
+ 		*objargs = lappend(*objargs,
+ 						   format_type_be_qualified(oprForm->oprleft));
+ 	if (oprForm->oprright)
+ 		*objargs = lappend(*objargs,
+ 						   format_type_be_qualified(oprForm->oprright));
+ 
+ 	ReleaseSysCache(opertup);
+ }
+ 
  /*
   * regoperatorout		- converts operator OID to "opr_name(args)"
   */
*** a/src/include/catalog/objectaddress.h
--- b/src/include/catalog/objectaddress.h
***************
*** 55,61 **** extern HeapTuple get_catalog_object_by_oid(Relation catalog,
--- 55,64 ----
  extern char *getObjectDescription(const ObjectAddress *object);
  extern char *getObjectDescriptionOids(Oid classid, Oid objid);
  
+ extern int unstringify_objtype(const char *objtype);
  extern char *getObjectTypeDescription(const ObjectAddress *object);
  extern char *getObjectIdentity(const ObjectAddress *address);
+ extern char *getObjectIdentityParts(const ObjectAddress *address,
+ 					   List **objname, List **objargs);
  
  #endif   /* OBJECTADDRESS_H */
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 4978,4984 **** DATA(insert OID = 3785 (  pg_logical_slot_peek_binary_changes PGNSP PGUID 12 100
  DESCR("peek at binary changes from replication slot");
  
  /* event triggers */
! DATA(insert OID = 3566 (  pg_event_trigger_dropped_objects		PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,25,25,25,25}" "{o,o,o,o,o,o,o}" "{classid, objid, objsubid, object_type, schema_name, object_name, object_identity}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ ));
  DESCR("list objects dropped by the current command");
  
  /* generic transition functions for ordered-set aggregates */
--- 4978,4984 ----
  DESCR("peek at binary changes from replication slot");
  
  /* event triggers */
! DATA(insert OID = 3566 (  pg_event_trigger_dropped_objects		PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,16,16,25,25,25,25,1009,1009}" "{o,o,o,o,o,o,o,o,o,o,o}" "{classid, objid, objsubid, original, normal, object_type, schema_name, object_name, object_identity, address_names, address_args}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ ));
  DESCR("list objects dropped by the current command");
  
  /* generic transition functions for ordered-set aggregates */
*** a/src/include/commands/event_trigger.h
--- b/src/include/commands/event_trigger.h
***************
*** 50,55 **** extern void EventTriggerSQLDrop(Node *parsetree);
  extern bool EventTriggerBeginCompleteQuery(void);
  extern void EventTriggerEndCompleteQuery(void);
  extern bool trackDroppedObjectsNeeded(void);
! extern void EventTriggerSQLDropAddObject(ObjectAddress *object);
  
  #endif   /* EVENT_TRIGGER_H */
--- 50,56 ----
  extern bool EventTriggerBeginCompleteQuery(void);
  extern void EventTriggerEndCompleteQuery(void);
  extern bool trackDroppedObjectsNeeded(void);
! extern void EventTriggerSQLDropAddObject(const ObjectAddress *object,
! 							 bool original, bool normal);
  
  #endif   /* EVENT_TRIGGER_H */
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
***************
*** 1192,1201 **** typedef enum ObjectType
--- 1192,1203 ----
  	OBJECT_ATTRIBUTE,			/* type's attribute, when distinct from column */
  	OBJECT_CAST,
  	OBJECT_COLUMN,
+ 	OBJECT_COMPOSITE,
  	OBJECT_CONSTRAINT,
  	OBJECT_COLLATION,
  	OBJECT_CONVERSION,
  	OBJECT_DATABASE,
+ 	OBJECT_DEFAULT,
  	OBJECT_DOMAIN,
  	OBJECT_EVENT_TRIGGER,
  	OBJECT_EXTENSION,
***************
*** 1222,1227 **** typedef enum ObjectType
--- 1224,1230 ----
  	OBJECT_TSPARSER,
  	OBJECT_TSTEMPLATE,
  	OBJECT_TYPE,
+ 	OBJECT_USER_MAPPING,
  	OBJECT_VIEW
  } ObjectType;
  
*** a/src/include/parser/parse_type.h
--- b/src/include/parser/parse_type.h
***************
*** 47,52 **** extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod);
--- 47,53 ----
  
  extern Oid	typeidTypeRelid(Oid type_id);
  
+ extern TypeName *typeStringToTypeName(const char *str);
  extern void parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok);
  
  #define ISCOMPLEX(typeid) (typeidTypeRelid(typeid) != InvalidOid)
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
***************
*** 641,648 **** extern Datum text_regclass(PG_FUNCTION_ARGS);
--- 641,652 ----
  extern List *stringToQualifiedNameList(const char *string);
  extern char *format_procedure(Oid procedure_oid);
  extern char *format_procedure_qualified(Oid procedure_oid);
+ extern void format_procedure_parts(Oid operator_oid, List **objnames,
+ 					  List **objargs);
  extern char *format_operator(Oid operator_oid);
  extern char *format_operator_qualified(Oid operator_oid);
+ extern void format_operator_parts(Oid operator_oid, List **objnames,
+ 					  List **objargs);
  
  /* rowtypes.c */
  extern Datum record_in(PG_FUNCTION_ARGS);
-- 
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