Alvaro Herrera wrote:
> Andres Freund wrote:
> 
> > Having reread the patch just now I basically see two things to
> > criticize:
> > a) why isn't this accessible at SQL level? That seems easy to address.
> > b) Arguably some of this could well be done in separate commits.
> 
> Fair comments.  I will split it up.

Here's a split version.  The last part is still missing some polish --
in particular handling for OBJECT_POLICY, and the SQL interface which
would also allow us to get something in the regression tests.


Note: in this patch series you can find the ObjectTypeMap thing that you
thought was obsolete in the DDL deparse patch ...

-- 
Álvaro Herrera                http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
>From 92816868c1c717519a76a83e65cd0b48e3726fbf Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvhe...@alvh.no-ip.org>
Date: Fri, 4 Apr 2014 16:05:48 -0300
Subject: [PATCH 1/3] add normal/original flags to
 pg_event_trigger_dropped_objects

---
 doc/src/sgml/func.sgml                      | 13 ++++++++++
 src/backend/catalog/dependency.c            | 21 ++++++++++-----
 src/backend/commands/event_trigger.c        | 16 +++++++++---
 src/include/catalog/pg_proc.h               |  2 +-
 src/include/commands/event_trigger.h        |  3 ++-
 src/test/regress/expected/event_trigger.out | 40 +++++++++++++++++++++++++++++
 src/test/regress/sql/event_trigger.sql      | 30 ++++++++++++++++++++++
 7 files changed, 114 insertions(+), 11 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 7e5bcd9..45f3efa 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -17583,6 +17583,19 @@ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
         <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>
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 256486c..6485e3d 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -205,16 +205,25 @@ deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel,
 	/*
 	 * Keep track of objects for event triggers, if necessary.
 	 */
-	if (trackDroppedObjectsNeeded())
+	if (trackDroppedObjectsNeeded() && !(flags & PERFORM_DELETION_INTERNAL))
 	{
 		for (i = 0; i < targetObjects->numrefs; i++)
 		{
-			ObjectAddress *thisobj = targetObjects->refs + i;
-
-			if ((!(flags & PERFORM_DELETION_INTERNAL)) &&
-				EventTriggerSupportsObjectClass(getObjectClass(thisobj)))
+			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);
+				EventTriggerSQLDropAddObject(thisobj, original, normal);
 			}
 		}
 	}
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 1b8c94b..0bab971 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -112,6 +112,8 @@ typedef struct SQLDropObject
 	const char *objname;
 	const char *objidentity;
 	const char *objecttype;
+	bool		original;
+	bool		normal;
 	slist_node	next;
 } SQLDropObject;
 
@@ -1105,7 +1107,7 @@ trackDroppedObjectsNeeded(void)
  * Register one object as being dropped by the current command.
  */
 void
-EventTriggerSQLDropAddObject(ObjectAddress *object)
+EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
 {
 	SQLDropObject *obj;
 	MemoryContext oldcxt;
@@ -1124,6 +1126,8 @@ EventTriggerSQLDropAddObject(ObjectAddress *object)
 
 	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;
@@ -1251,8 +1255,8 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
 	{
 		SQLDropObject *obj;
 		int			i = 0;
-		Datum		values[7];
-		bool		nulls[7];
+		Datum		values[9];
+		bool		nulls[9];
 
 		obj = slist_container(SQLDropObject, next, iter.cur);
 
@@ -1268,6 +1272,12 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
 		/* 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);
 
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 4736532..c4e932f 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4988,7 +4988,7 @@ 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_ ));
+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}" "{o,o,o,o,o,o,o,o,o}" "{classid, objid, objsubid, original, normal, 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 */
diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h
index 0233f4c..7ef01cb 100644
--- a/src/include/commands/event_trigger.h
+++ b/src/include/commands/event_trigger.h
@@ -50,6 +50,7 @@ extern void EventTriggerSQLDrop(Node *parsetree);
 extern bool EventTriggerBeginCompleteQuery(void);
 extern void EventTriggerEndCompleteQuery(void);
 extern bool trackDroppedObjectsNeeded(void);
-extern void EventTriggerSQLDropAddObject(ObjectAddress *object);
+extern void EventTriggerSQLDropAddObject(const ObjectAddress *object,
+							 bool original, bool normal);
 
 #endif   /* EVENT_TRIGGER_H */
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index d4723b2..cb21792 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -294,3 +294,43 @@ SELECT * FROM dropped_objects WHERE type = 'schema';
 DROP ROLE regression_bob;
 DROP EVENT TRIGGER regress_event_trigger_drop_objects;
 DROP EVENT TRIGGER undroppable;
+CREATE OR REPLACE FUNCTION event_trigger_report_dropped()
+ RETURNS event_trigger
+ LANGUAGE plpgsql
+AS $$
+DECLARE r record;
+BEGIN
+    FOR r IN SELECT * from pg_event_trigger_dropped_objects()
+    LOOP
+    IF NOT r.normal AND NOT r.original THEN
+        CONTINUE;
+    END IF;
+    RAISE NOTICE 'NORMAL: orig=% normal=% type=% identity=%',
+        r.original, r.normal, r.object_type, r.object_identity;
+    END LOOP;
+END; $$;
+CREATE EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop
+    EXECUTE PROCEDURE event_trigger_report_dropped();
+CREATE SCHEMA evttrig
+	CREATE TABLE one (col_a SERIAL PRIMARY KEY, col_b text DEFAULT 'forty two')
+	CREATE INDEX one_idx ON one (col_b)
+	CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42);
+ALTER TABLE evttrig.two DROP COLUMN col_c;
+NOTICE:  NORMAL: orig=t normal=f type=table column identity=evttrig.two.col_c
+NOTICE:  NORMAL: orig=f normal=t type=table constraint identity=two_col_c_check on evttrig.two
+ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT;
+NOTICE:  NORMAL: orig=t normal=f type=default value identity=for evttrig.one.col_b
+ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey;
+NOTICE:  NORMAL: orig=t normal=f type=table constraint identity=one_pkey on evttrig.one
+DROP INDEX evttrig.one_idx;
+NOTICE:  NORMAL: orig=t normal=f type=index identity=evttrig.one_idx
+DROP SCHEMA evttrig CASCADE;
+NOTICE:  drop cascades to 2 other objects
+DETAIL:  drop cascades to table evttrig.one
+drop cascades to table evttrig.two
+NOTICE:  NORMAL: orig=t normal=f type=schema identity=evttrig
+NOTICE:  NORMAL: orig=f normal=t type=table identity=evttrig.one
+NOTICE:  NORMAL: orig=f normal=t type=sequence identity=evttrig.one_col_a_seq
+NOTICE:  NORMAL: orig=f normal=t type=default value identity=for evttrig.one.col_a
+NOTICE:  NORMAL: orig=f normal=t type=table identity=evttrig.two
+DROP EVENT TRIGGER regress_event_trigger_report_dropped;
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 11d2ce5..c82380b 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -206,3 +206,33 @@ DROP ROLE regression_bob;
 
 DROP EVENT TRIGGER regress_event_trigger_drop_objects;
 DROP EVENT TRIGGER undroppable;
+
+CREATE OR REPLACE FUNCTION event_trigger_report_dropped()
+ RETURNS event_trigger
+ LANGUAGE plpgsql
+AS $$
+DECLARE r record;
+BEGIN
+    FOR r IN SELECT * from pg_event_trigger_dropped_objects()
+    LOOP
+    IF NOT r.normal AND NOT r.original THEN
+        CONTINUE;
+    END IF;
+    RAISE NOTICE 'NORMAL: orig=% normal=% type=% identity=%',
+        r.original, r.normal, r.object_type, r.object_identity;
+    END LOOP;
+END; $$;
+CREATE EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop
+    EXECUTE PROCEDURE event_trigger_report_dropped();
+CREATE SCHEMA evttrig
+	CREATE TABLE one (col_a SERIAL PRIMARY KEY, col_b text DEFAULT 'forty two')
+	CREATE INDEX one_idx ON one (col_b)
+	CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42);
+
+ALTER TABLE evttrig.two DROP COLUMN col_c;
+ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT;
+ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey;
+DROP INDEX evttrig.one_idx;
+DROP SCHEMA evttrig CASCADE;
+
+DROP EVENT TRIGGER regress_event_trigger_report_dropped;
-- 
1.9.1

>From a424f151c888aa6e94867da2edfe84f251f2798a Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvhe...@alvh.no-ip.org>
Date: Wed, 15 Oct 2014 18:02:45 -0300
Subject: [PATCH 2/3] add support for OBJECT_DEFAULT in get_object_address

---
 src/backend/catalog/objectaddress.c  | 91 ++++++++++++++++++++++++++++++++++++
 src/backend/commands/event_trigger.c |  1 +
 src/include/nodes/parsenodes.h       |  1 +
 3 files changed, 93 insertions(+)

diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index b69b75b..a443e84 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -441,6 +441,9 @@ static ObjectAddress get_object_address_relobject(ObjectType objtype,
 static ObjectAddress get_object_address_attribute(ObjectType objtype,
 							 List *objname, Relation *relp,
 							 LOCKMODE lockmode, bool missing_ok);
+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);
 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *objname,
@@ -528,6 +531,12 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 												 &relation, lockmode,
 												 missing_ok);
 				break;
+			case OBJECT_DEFAULT:
+				address =
+					get_object_address_attrdef(objtype, objname,
+											   &relation, lockmode,
+											   missing_ok);
+				break;
 			case OBJECT_RULE:
 			case OBJECT_TRIGGER:
 			case OBJECT_CONSTRAINT:
@@ -1080,6 +1089,88 @@ get_object_address_attribute(ObjectType objtype, List *objname,
 }
 
 /*
+ * Find the ObjectAddress for an attribute's default value.
+ */
+static ObjectAddress
+get_object_address_attrdef(ObjectType objtype, List *objname,
+						   Relation *relp, LOCKMODE lockmode,
+						   bool missing_ok)
+{
+	ObjectAddress address;
+	List	   *relname;
+	Oid			reloid;
+	Relation	relation;
+	const char *attname;
+	AttrNumber	attnum;
+	TupleDesc	tupdesc;
+	Oid			defoid;
+
+	/* Extract relation name and open relation. */
+	if (list_length(objname) < 2)
+		ereport(ERROR,
+				(errcode(ERRCODE_SYNTAX_ERROR),
+				 errmsg("column name must be qualified")));
+	attname = strVal(llast(objname));
+	relname = list_truncate(list_copy(objname), list_length(objname) - 1);
+	/* XXX no missing_ok support here */
+	relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
+	reloid = RelationGetRelid(relation);
+
+	tupdesc = RelationGetDescr(relation);
+
+	/* Look up attribute number and scan pg_attrdef to find its tuple */
+	attnum = get_attnum(reloid, attname);
+	defoid = InvalidOid;
+	if (attnum != InvalidAttrNumber && tupdesc->constr != NULL)
+	{
+		Relation	attrdef;
+		ScanKeyData	keys[2];
+		SysScanDesc	scan;
+		HeapTuple	tup;
+
+		attrdef = relation_open(AttrDefaultRelationId, AccessShareLock);
+		ScanKeyInit(&keys[0],
+					Anum_pg_attrdef_adrelid,
+					BTEqualStrategyNumber,
+					F_OIDEQ,
+					ObjectIdGetDatum(reloid));
+		ScanKeyInit(&keys[1],
+					Anum_pg_attrdef_adnum,
+					BTEqualStrategyNumber,
+					F_INT2EQ,
+					Int16GetDatum(attnum));
+		scan = systable_beginscan(attrdef, AttrDefaultIndexId, true,
+								  NULL, 2, keys);
+		if (HeapTupleIsValid(tup = systable_getnext(scan)))
+			defoid = HeapTupleGetOid(tup);
+
+		systable_endscan(scan);
+		relation_close(attrdef, AccessShareLock);
+	}
+	if (!OidIsValid(defoid))
+	{
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_COLUMN),
+					 errmsg("default value for column \"%s\" of relation \"%s\" does not exist",
+							attname, NameListToString(relname))));
+
+		address.classId = AttrDefaultRelationId;
+		address.objectId = InvalidOid;
+		address.objectSubId = InvalidAttrNumber;
+		relation_close(relation, lockmode);
+		return address;
+	}
+
+	address.classId = AttrDefaultRelationId;
+	address.objectId = defoid;
+	address.objectSubId = 0;
+
+	*relp = relation;
+	return address;
+}
+
+/*
  * Find the ObjectAddress for a type or domain
  */
 static ObjectAddress
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 0bab971..6cb067e 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -926,6 +926,7 @@ EventTriggerSupportsObjectType(ObjectType obtype)
 		case OBJECT_CONSTRAINT:
 		case OBJECT_COLLATION:
 		case OBJECT_CONVERSION:
+		case OBJECT_DEFAULT:
 		case OBJECT_DOMAIN:
 		case OBJECT_EXTENSION:
 		case OBJECT_FDW:
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index cef9544..5a092d8 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1212,6 +1212,7 @@ typedef enum ObjectType
 	OBJECT_COLLATION,
 	OBJECT_CONVERSION,
 	OBJECT_DATABASE,
+	OBJECT_DEFAULT,
 	OBJECT_DOMAIN,
 	OBJECT_EVENT_TRIGGER,
 	OBJECT_EXTENSION,
-- 
1.9.1

>From 5525571e41b91ff70c03b08ac914c020dc489e87 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvhe...@alvh.no-ip.org>
Date: Wed, 15 Oct 2014 18:03:22 -0300
Subject: [PATCH 3/3] add objname/objargs support

---
 doc/src/sgml/func.sgml               |  16 ++
 src/backend/catalog/objectaddress.c  | 315 ++++++++++++++++++++++++++++++++---
 src/backend/commands/alter.c         |   3 +-
 src/backend/commands/event_trigger.c |  57 ++++++-
 src/backend/commands/tablecmds.c     |   2 +-
 src/backend/parser/gram.y            |  16 +-
 src/backend/parser/parse_type.c      |  46 +++--
 src/backend/parser/parse_utilcmd.c   |   2 +-
 src/backend/tcop/utility.c           |   5 +-
 src/backend/utils/adt/regproc.c      |  60 +++++++
 src/include/catalog/objectaddress.h  |   3 +
 src/include/catalog/pg_proc.h        |   3 +-
 src/include/nodes/parsenodes.h       |   5 +-
 src/include/parser/parse_type.h      |   1 +
 src/include/utils/builtins.h         |   4 +
 15 files changed, 481 insertions(+), 57 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 45f3efa..dec2a67 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -17625,6 +17625,22 @@ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
          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>
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index a443e84..4d0726c 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -431,6 +431,97 @@ static const ObjectPropertyType ObjectProperty[] =
 	}
 };
 
+/*
+ * 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.
+ *
+ * To ease maintenance, 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_TABCONSTRAINT },
+	{ "domain constraint", OBJECT_DOMCONSTRAINT },
+	/* 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 },		/* unmapped */
+	/* 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,
@@ -456,8 +547,9 @@ 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);
+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
@@ -539,11 +631,28 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 				break;
 			case OBJECT_RULE:
 			case OBJECT_TRIGGER:
-			case OBJECT_CONSTRAINT:
+			case OBJECT_TABCONSTRAINT:
 			case OBJECT_POLICY:
 				address = get_object_address_relobject(objtype, objname,
 													   &relation, missing_ok);
 				break;
+			case OBJECT_DOMCONSTRAINT:
+				{
+					List		   *domname;
+					ObjectAddress	domaddr;
+					char		   *constrname;
+
+					domname = list_truncate(list_copy(objname), list_length(objname) - 1);
+					constrname = strVal(llast(objname));
+					domaddr = get_object_address_type(OBJECT_DOMAIN, domname, missing_ok);
+
+					address.classId = ConstraintRelationId;
+					address.objectId = get_domain_constraint_oid(domaddr.objectId,
+															  constrname, missing_ok);
+					address.objectSubId = 0;
+
+				}
+				break;
 			case OBJECT_DATABASE:
 			case OBJECT_EXTENSION:
 			case OBJECT_TABLESPACE:
@@ -943,7 +1052,7 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 	const char *depname;
 
 	/* Extract name of dependent object. */
-	depname = strVal(lfirst(list_tail(objname)));
+	depname = strVal(llast(objname));
 
 	/* Separate relation name from dependent object name. */
 	nnames = list_length(objname);
@@ -999,7 +1108,7 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 					get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
 				address.objectSubId = 0;
 				break;
-			case OBJECT_CONSTRAINT:
+			case OBJECT_TABCONSTRAINT:
 				address.classId = ConstraintRelationId;
 				address.objectId = relation ?
 					get_relation_constraint_oid(reloid, depname, missing_ok) :
@@ -1269,7 +1378,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
 		case OBJECT_RULE:
 		case OBJECT_TRIGGER:
 		case OBJECT_POLICY:
-		case OBJECT_CONSTRAINT:
+		case OBJECT_TABCONSTRAINT:
 			if (!pg_class_ownercheck(RelationGetRelid(relation), roleid))
 				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
 							   RelationGetRelationName(relation));
@@ -1282,6 +1391,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
 		case OBJECT_TYPE:
 		case OBJECT_DOMAIN:
 		case OBJECT_ATTRIBUTE:
+		case OBJECT_DOMCONSTRAINT:
 			if (!pg_type_ownercheck(address.objectId, roleid))
 				aclcheck_error_type(ACLCHECK_NOT_OWNER, address.objectId);
 			break;
@@ -1461,6 +1571,34 @@ get_object_namespace(const ObjectAddress *address)
 }
 
 /*
+ * 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
@@ -2591,6 +2729,8 @@ pg_identify_object(PG_FUNCTION_ARGS)
 /*
  * 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)
@@ -2838,7 +2978,7 @@ getProcedureTypeDescription(StringInfo buffer, Oid procid)
 }
 
 /*
- * Return a palloc'ed string that identifies an object.
+ * 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.
@@ -2846,14 +2986,42 @@ getProcedureTypeDescription(StringInfo buffer, Oid procid)
 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; and
+	 * initialize them to empty lists.  For objname this is useless because it
+	 * will be initialized in all cases inside the switch; but we do it anyway
+	 * so that we can Assert() below that no branch leaves it unset.
+	 */
+	Assert(PointerIsValid(objname) == PointerIsValid(objargs));
+	if (objname)
+	{
+		*objname = NIL;
+		*objargs = NIL;
+	}
+
 	switch (getObjectClass(object))
 	{
 		case OCLASS_CLASS:
-			getRelationIdentity(&buffer, object->objectId);
+			getRelationIdentity(&buffer, object->objectId, objname);
 			if (object->objectSubId != 0)
 			{
 				char	   *attr;
@@ -2861,17 +3029,27 @@ getObjectIdentity(const ObjectAddress *object)
 				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:
-			appendStringInfoString(&buffer,
-								 format_type_be_qualified(object->objectId));
+			{
+				char *typeout;
+
+				typeout = format_type_be_qualified(object->objectId);
+				appendStringInfoString(&buffer, typeout);
+				if (objname)
+					*objname = list_make1(typeout);
+			}
 			break;
 
 		case OCLASS_CAST:
@@ -2894,6 +3072,10 @@ getObjectIdentity(const ObjectAddress *object)
 							  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;
 			}
@@ -2914,6 +3096,8 @@ getObjectIdentity(const ObjectAddress *object)
 				appendStringInfoString(&buffer,
 									   quote_qualified_identifier(schema,
 												   NameStr(coll->collname)));
+				if (objname)
+					*objname = list_make2(schema, NameStr(coll->collname));
 				ReleaseSysCache(collTup);
 				break;
 			}
@@ -2934,7 +3118,9 @@ getObjectIdentity(const ObjectAddress *object)
 				{
 					appendStringInfo(&buffer, "%s on ",
 									 quote_identifier(NameStr(con->conname)));
-					getRelationIdentity(&buffer, con->conrelid);
+					getRelationIdentity(&buffer, con->conrelid, objname);
+					if (objname)
+						*objname = lappend(*objname, pstrdup(NameStr(con->conname)));
 				}
 				else
 				{
@@ -2946,7 +3132,10 @@ getObjectIdentity(const ObjectAddress *object)
 
 					appendStringInfo(&buffer, "%s on %s",
 									 quote_identifier(NameStr(con->conname)),
-									 getObjectIdentity(&domain));
+									 getObjectIdentityParts(&domain, objname,
+															objargs));
+					if (objname)
+						*objname = lappend(*objname, pstrdup(NameStr(con->conname)));
 				}
 
 				ReleaseSysCache(conTup);
@@ -2966,6 +3155,8 @@ getObjectIdentity(const ObjectAddress *object)
 				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;
 			}
@@ -3003,7 +3194,8 @@ getObjectIdentity(const ObjectAddress *object)
 				colobject.objectSubId = attrdef->adnum;
 
 				appendStringInfo(&buffer, "for %s",
-								 getObjectIdentity(&colobject));
+								 getObjectIdentityParts(&colobject,
+														objname, objargs));
 
 				systable_endscan(adscan);
 				heap_close(attrdefDesc, AccessShareLock);
@@ -3023,17 +3215,23 @@ getObjectIdentity(const ObjectAddress *object)
 				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:
@@ -3064,14 +3262,19 @@ getObjectIdentity(const ObjectAddress *object)
 												 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);
+			getOpFamilyIdentity(&buffer, object->objectId, objname, objargs);
 			break;
 
 		case OCLASS_AMOP:
@@ -3083,6 +3286,10 @@ getObjectIdentity(const ObjectAddress *object)
 				Form_pg_amop amopForm;
 				StringInfoData opfam;
 
+				/* no objname support here */
+				if (objname)
+					*objname = NIL;
+
 				amopDesc = heap_open(AccessMethodOperatorRelationId,
 									 AccessShareLock);
 
@@ -3103,7 +3310,7 @@ getObjectIdentity(const ObjectAddress *object)
 				amopForm = (Form_pg_amop) GETSTRUCT(tup);
 
 				initStringInfo(&opfam);
-				getOpFamilyIdentity(&opfam, amopForm->amopfamily);
+				getOpFamilyIdentity(&opfam, amopForm->amopfamily, NULL, NULL);
 
 				appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
 								 amopForm->amopstrategy,
@@ -3127,6 +3334,10 @@ getObjectIdentity(const ObjectAddress *object)
 				Form_pg_amproc amprocForm;
 				StringInfoData opfam;
 
+				/* no objname support here */
+				if (objname)
+					*objname = NIL;
+
 				amprocDesc = heap_open(AccessMethodProcedureRelationId,
 									   AccessShareLock);
 
@@ -3147,7 +3358,7 @@ getObjectIdentity(const ObjectAddress *object)
 				amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
 
 				initStringInfo(&opfam);
-				getOpFamilyIdentity(&opfam, amprocForm->amprocfamily);
+				getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, NULL, NULL);
 
 				appendStringInfo(&buffer, "function %d (%s, %s) of %s",
 								 amprocForm->amprocnum,
@@ -3180,7 +3391,9 @@ getObjectIdentity(const ObjectAddress *object)
 
 				appendStringInfo(&buffer, "%s on ",
 								 quote_identifier(NameStr(rule->rulename)));
-				getRelationIdentity(&buffer, rule->ev_class);
+				getRelationIdentity(&buffer, rule->ev_class, objname);
+				if (objname)
+					*objname = lappend(*objname, NameStr(rule->rulename));
 
 				heap_close(ruleDesc, AccessShareLock);
 				break;
@@ -3204,7 +3417,9 @@ getObjectIdentity(const ObjectAddress *object)
 
 				appendStringInfo(&buffer, "%s on ",
 								 quote_identifier(NameStr(trig->tgname)));
-				getRelationIdentity(&buffer, trig->tgrelid);
+				getRelationIdentity(&buffer, trig->tgrelid, objname);
+				if (objname)
+					*objname = lappend(*objname, NameStr(trig->tgname));
 
 				heap_close(trigDesc, AccessShareLock);
 				break;
@@ -3220,6 +3435,8 @@ getObjectIdentity(const ObjectAddress *object)
 						 object->objectId);
 				appendStringInfoString(&buffer,
 									   quote_identifier(nspname));
+				if (objname)
+					*objname = list_make1(nspname);
 				break;
 			}
 
@@ -3239,6 +3456,9 @@ getObjectIdentity(const ObjectAddress *object)
 				appendStringInfoString(&buffer,
 									   quote_qualified_identifier(schema,
 											  NameStr(formParser->prsname)));
+				if (objname)
+					*objname = list_make2(schema,
+										  pstrdup(NameStr(formParser->prsname)));
 				ReleaseSysCache(tup);
 				break;
 			}
@@ -3259,6 +3479,9 @@ getObjectIdentity(const ObjectAddress *object)
 				appendStringInfoString(&buffer,
 									   quote_qualified_identifier(schema,
 											   NameStr(formDict->dictname)));
+				if (objname)
+					*objname = list_make2(schema,
+										  pstrdup(NameStr(formDict->dictname)));
 				ReleaseSysCache(tup);
 				break;
 			}
@@ -3279,7 +3502,9 @@ getObjectIdentity(const ObjectAddress *object)
 				appendStringInfoString(&buffer,
 									   quote_qualified_identifier(schema,
 											   NameStr(formTmpl->tmplname)));
-				pfree(schema);
+				if (objname)
+					*objname = list_make2(schema,
+										  pstrdup(NameStr(formTmpl->tmplname)));
 				ReleaseSysCache(tup);
 				break;
 			}
@@ -3300,6 +3525,9 @@ getObjectIdentity(const ObjectAddress *object)
 				appendStringInfoString(&buffer,
 									   quote_qualified_identifier(schema,
 												 NameStr(formCfg->cfgname)));
+				if (objname)
+					*objname = list_make2(schema,
+										  pstrdup(NameStr(formCfg->cfgname)));
 				ReleaseSysCache(tup);
 				break;
 			}
@@ -3308,6 +3536,9 @@ getObjectIdentity(const ObjectAddress *object)
 			{
 				char	   *username;
 
+				/* no objname support here */
+				Assert(objname == NULL);
+
 				username = GetUserNameFromId(object->objectId);
 				appendStringInfoString(&buffer,
 									   quote_identifier(username));
@@ -3318,6 +3549,9 @@ getObjectIdentity(const ObjectAddress *object)
 			{
 				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",
@@ -3331,6 +3565,9 @@ getObjectIdentity(const ObjectAddress *object)
 			{
 				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",
@@ -3346,6 +3583,8 @@ getObjectIdentity(const ObjectAddress *object)
 
 				fdw = GetForeignDataWrapper(object->objectId);
 				appendStringInfoString(&buffer, quote_identifier(fdw->fdwname));
+				if (objname)
+					*objname = list_make1(pstrdup(fdw->fdwname));
 				break;
 			}
 
@@ -3356,6 +3595,8 @@ getObjectIdentity(const ObjectAddress *object)
 				srv = GetForeignServer(object->objectId);
 				appendStringInfoString(&buffer,
 									   quote_identifier(srv->servername));
+				if (objname)
+					*objname = list_make1(pstrdup(srv->servername));
 				break;
 			}
 
@@ -3365,6 +3606,8 @@ getObjectIdentity(const ObjectAddress *object)
 				Oid			useid;
 				const char *usename;
 
+				/* XXX get_object_address doesn't seem to support this */
+
 				tup = SearchSysCache1(USERMAPPINGOID,
 									  ObjectIdGetDatum(object->objectId));
 				if (!HeapTupleIsValid(tup))
@@ -3389,10 +3632,15 @@ getObjectIdentity(const ObjectAddress *object)
 				Relation	defaclrel;
 				ScanKeyData skey[1];
 				SysScanDesc rcscan;
-
 				HeapTuple	tup;
 				Form_pg_default_acl defacl;
 
+				/*
+				 * There is no valid representation for default ACL objects for
+				 * get_object_address; disallow callers from asking for it.
+				 */
+				Assert(!objname);
+
 				defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
 
 				ScanKeyInit(&skey[0],
@@ -3459,6 +3707,8 @@ getObjectIdentity(const ObjectAddress *object)
 					elog(ERROR, "cache lookup failed for extension %u",
 						 object->objectId);
 				appendStringInfoString(&buffer, quote_identifier(extname));
+				if (objname)
+					*objname = list_make1(extname);
 				break;
 			}
 
@@ -3467,6 +3717,9 @@ getObjectIdentity(const ObjectAddress *object)
 				HeapTuple	tup;
 				Form_pg_event_trigger trigForm;
 
+				/* no objname support here */
+				Assert(objname == NULL);
+
 				tup = SearchSysCache1(EVENTTRIGGEROID,
 									  ObjectIdGetDatum(object->objectId));
 				if (!HeapTupleIsValid(tup))
@@ -3487,11 +3740,18 @@ getObjectIdentity(const ObjectAddress *object)
 			break;
 	}
 
+	/*
+	 * If a get_object_address representation was requested, make sure we are
+	 * providing one.  We don't check for objargs, because many of the cases
+	 * above leave it as NIL.
+	 */
+	Assert(!objname || *objname != NIL);
+
 	return buffer.data;
 }
 
 static void
-getOpFamilyIdentity(StringInfo buffer, Oid opfid)
+getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **objname, List **objargs)
 {
 	HeapTuple	opfTup;
 	Form_pg_opfamily opfForm;
@@ -3516,6 +3776,13 @@ getOpFamilyIdentity(StringInfo buffer, Oid opfid)
 												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);
 }
@@ -3525,7 +3792,7 @@ getOpFamilyIdentity(StringInfo buffer, Oid opfid)
  * StringInfo.
  */
 static void
-getRelationIdentity(StringInfo buffer, Oid relid)
+getRelationIdentity(StringInfo buffer, Oid relid, List **objname)
 {
 	HeapTuple	relTup;
 	Form_pg_class relForm;
@@ -3541,6 +3808,8 @@ getRelationIdentity(StringInfo buffer, Oid relid)
 	appendStringInfoString(buffer,
 						   quote_qualified_identifier(schema,
 												 NameStr(relForm->relname)));
+	if (objname)
+		*objname = list_make2(schema, pstrdup(NameStr(relForm->relname)));
 
 	ReleaseSysCache(relTup);
 }
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index c9a9baf..e7f4ef3 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -305,7 +305,8 @@ ExecRenameStmt(RenameStmt *stmt)
 {
 	switch (stmt->renameType)
 	{
-		case OBJECT_CONSTRAINT:
+		case OBJECT_TABCONSTRAINT:
+		case OBJECT_DOMCONSTRAINT:
 			return RenameConstraint(stmt);
 
 		case OBJECT_DATABASE:
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 6cb067e..bb55bbc 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -112,6 +112,8 @@ typedef struct SQLDropObject
 	const char *objname;
 	const char *objidentity;
 	const char *objecttype;
+	List	   *addrnames;
+	List	   *addrargs;
 	bool		original;
 	bool		normal;
 	slist_node	next;
@@ -923,11 +925,12 @@ EventTriggerSupportsObjectType(ObjectType obtype)
 		case OBJECT_ATTRIBUTE:
 		case OBJECT_CAST:
 		case OBJECT_COLUMN:
-		case OBJECT_CONSTRAINT:
+		case OBJECT_COMPOSITE:
 		case OBJECT_COLLATION:
 		case OBJECT_CONVERSION:
 		case OBJECT_DEFAULT:
 		case OBJECT_DOMAIN:
+		case OBJECT_DOMCONSTRAINT:
 		case OBJECT_EXTENSION:
 		case OBJECT_FDW:
 		case OBJECT_FOREIGN_SERVER:
@@ -944,6 +947,7 @@ EventTriggerSupportsObjectType(ObjectType obtype)
 		case OBJECT_RULE:
 		case OBJECT_SCHEMA:
 		case OBJECT_SEQUENCE:
+		case OBJECT_TABCONSTRAINT:
 		case OBJECT_TABLE:
 		case OBJECT_TRIGGER:
 		case OBJECT_TSCONFIGURATION:
@@ -951,6 +955,7 @@ EventTriggerSupportsObjectType(ObjectType obtype)
 		case OBJECT_TSPARSER:
 		case OBJECT_TSTEMPLATE:
 		case OBJECT_TYPE:
+		case OBJECT_USER_MAPPING:
 		case OBJECT_VIEW:
 			return true;
 	}
@@ -1190,10 +1195,11 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
 		heap_close(catalog, AccessShareLock);
 	}
 
-	/* object identity */
-	obj->objidentity = getObjectIdentity(&obj->address);
+	/* object identity, objname and objargs */
+	obj->objidentity =
+		getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs);
 
-	/* and object type, too */
+	/* object type */
 	obj->objecttype = getObjectTypeDescription(&obj->address);
 
 	slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
@@ -1202,6 +1208,33 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
 }
 
 /*
+ * helper for pg_event_trigger_dropped_object
+ *
+ * Make an array of text Datum out of a list of C strings.
+ */
+static Datum
+strlist_to_textarray(List *list)
+{
+	ArrayType *arr;
+	Datum	*datums;
+	int		j = 0;
+	ListCell *cell;
+
+	datums = palloc(sizeof(text *) * list_length(list));
+	foreach(cell, list)
+	{
+		char   *name = lfirst(cell);
+
+		datums[j++] = CStringGetTextDatum(name);
+	}
+
+	arr = construct_array(datums, list_length(list),
+						  TEXTOID, -1, false, 'i');
+
+	return PointerGetDatum(arr);
+}
+
+/*
  * pg_event_trigger_dropped_objects
  *
  * Make the list of dropped objects available to the user function run by the
@@ -1256,8 +1289,8 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
 	{
 		SQLDropObject *obj;
 		int			i = 0;
-		Datum		values[9];
-		bool		nulls[9];
+		Datum		values[11];
+		bool		nulls[11];
 
 		obj = slist_container(SQLDropObject, next, iter.cur);
 
@@ -1300,6 +1333,18 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
 		else
 			nulls[i++] = true;
 
+		/* address_names */
+		if (obj->addrnames)
+			values[i++] = strlist_to_textarray(obj->addrnames);
+		else
+			nulls[i++] = true;
+
+		/* address_args */
+		if (obj->addrargs)
+			values[i++] = strlist_to_textarray(obj->addrargs);
+		else
+			nulls[i++] = true;
+
 		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
 	}
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index ecdff1e..c6e06f0 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -2457,7 +2457,7 @@ RenameConstraint(RenameStmt *stmt)
 	Oid			relid = InvalidOid;
 	Oid			typid = InvalidOid;
 
-	if (stmt->relationType == OBJECT_DOMAIN)
+	if (stmt->renameType == OBJECT_DOMCONSTRAINT)
 	{
 		Relation	rel;
 		HeapTuple	tup;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c98c27a..8ea581e 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -5611,12 +5611,21 @@ CommentStmt:
 			| COMMENT ON CONSTRAINT name ON any_name IS comment_text
 				{
 					CommentStmt *n = makeNode(CommentStmt);
-					n->objtype = OBJECT_CONSTRAINT;
+					n->objtype = OBJECT_TABCONSTRAINT;
 					n->objname = lappend($6, makeString($4));
 					n->objargs = NIL;
 					n->comment = $8;
 					$$ = (Node *) n;
 				}
+			| COMMENT ON CONSTRAINT name ON DOMAIN_P any_name IS comment_text
+				{
+					CommentStmt *n = makeNode(CommentStmt);
+					n->objtype = OBJECT_DOMCONSTRAINT;
+					n->objname = lappend($7, makeString($4));
+					n->objargs = NIL;
+					n->comment = $9;
+					$$ = (Node *) n;
+				}
 			| COMMENT ON RULE name ON any_name IS comment_text
 				{
 					CommentStmt *n = makeNode(CommentStmt);
@@ -7301,8 +7310,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
 			| ALTER DOMAIN_P any_name RENAME CONSTRAINT name TO name
 				{
 					RenameStmt *n = makeNode(RenameStmt);
-					n->renameType = OBJECT_CONSTRAINT;
-					n->relationType = OBJECT_DOMAIN;
+					n->renameType = OBJECT_DOMCONSTRAINT;
 					n->object = $3;
 					n->subname = $6;
 					n->newname = $8;
@@ -7570,7 +7578,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
 			| ALTER TABLE relation_expr RENAME CONSTRAINT name TO name
 				{
 					RenameStmt *n = makeNode(RenameStmt);
-					n->renameType = OBJECT_CONSTRAINT;
+					n->renameType = OBJECT_TABCONSTRAINT;
 					n->relationType = OBJECT_TABLE;
 					n->relation = $3;
 					n->subname = $6;
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index d0803df..299cc53 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -705,13 +705,11 @@ 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.
+ * the string and return the result as a TypeName.
+ * If the string cannot be parsed as a type, an error is raised.
  */
-void
-parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
-				bool missing_ok)
+TypeName *
+typeStringToTypeName(const char *str)
 {
 	StringInfoData buf;
 	List	   *raw_parsetree_list;
@@ -720,7 +718,6 @@ 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))
@@ -779,6 +776,7 @@ parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
 		typecast->arg == NULL ||
 		!IsA(typecast->arg, A_Const))
 		goto fail;
+
 	typeName = typecast->typeName;
 	if (typeName == NULL ||
 		!IsA(typeName, TypeName))
@@ -786,6 +784,31 @@ parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
 	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,13 +831,4 @@ 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)));
 }
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 7c1939f..04c8595 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -871,7 +871,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
 			{
 				CommentStmt *stmt = makeNode(CommentStmt);
 
-				stmt->objtype = OBJECT_CONSTRAINT;
+				stmt->objtype = OBJECT_TABCONSTRAINT;
 				stmt->objname = list_make3(makeString(cxt->relation->schemaname),
 										   makeString(cxt->relation->relname),
 										   makeString(n->conname));
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 4a2a339..2b93015 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1587,9 +1587,6 @@ AlterObjectTypeCommandTag(ObjectType objtype)
 		case OBJECT_COLUMN:
 			tag = "ALTER TABLE";
 			break;
-		case OBJECT_CONSTRAINT:
-			tag = "ALTER TABLE";
-			break;
 		case OBJECT_CONVERSION:
 			tag = "ALTER CONVERSION";
 			break;
@@ -1597,6 +1594,7 @@ AlterObjectTypeCommandTag(ObjectType objtype)
 			tag = "ALTER DATABASE";
 			break;
 		case OBJECT_DOMAIN:
+		case OBJECT_DOMCONSTRAINT:
 			tag = "ALTER DOMAIN";
 			break;
 		case OBJECT_EXTENSION:
@@ -1648,6 +1646,7 @@ AlterObjectTypeCommandTag(ObjectType objtype)
 			tag = "ALTER SEQUENCE";
 			break;
 		case OBJECT_TABLE:
+		case OBJECT_TABCONSTRAINT:
 			tag = "ALTER TABLE";
 			break;
 		case OBJECT_TABLESPACE:
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index c0314ee..8cda52b 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -439,6 +439,41 @@ format_procedure_internal(Oid procedure_oid, bool force_qualify)
 }
 
 /*
+ * 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,6 +910,31 @@ format_operator_qualified(Oid operator_oid)
 	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)"
  */
diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h
index 2a9431d..997a156 100644
--- a/src/include/catalog/objectaddress.h
+++ b/src/include/catalog/objectaddress.h
@@ -55,7 +55,10 @@ extern HeapTuple get_catalog_object_by_oid(Relation catalog,
 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 */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c4e932f..a5c8b05 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4988,7 +4988,8 @@ 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,16,16,25,25,25,25}" "{o,o,o,o,o,o,o,o,o}" "{classid, objid, objsubid, original, normal, object_type, schema_name, object_name, object_identity}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ ));
+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 */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 5a092d8..54f6082 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1208,12 +1208,13 @@ typedef enum ObjectType
 	OBJECT_ATTRIBUTE,			/* type's attribute, when distinct from column */
 	OBJECT_CAST,
 	OBJECT_COLUMN,
-	OBJECT_CONSTRAINT,
+	OBJECT_COMPOSITE,
 	OBJECT_COLLATION,
 	OBJECT_CONVERSION,
 	OBJECT_DATABASE,
 	OBJECT_DEFAULT,
 	OBJECT_DOMAIN,
+	OBJECT_DOMCONSTRAINT,
 	OBJECT_EVENT_TRIGGER,
 	OBJECT_EXTENSION,
 	OBJECT_FDW,
@@ -1232,6 +1233,7 @@ typedef enum ObjectType
 	OBJECT_RULE,
 	OBJECT_SCHEMA,
 	OBJECT_SEQUENCE,
+	OBJECT_TABCONSTRAINT,
 	OBJECT_TABLE,
 	OBJECT_TABLESPACE,
 	OBJECT_TRIGGER,
@@ -1240,6 +1242,7 @@ typedef enum ObjectType
 	OBJECT_TSPARSER,
 	OBJECT_TSTEMPLATE,
 	OBJECT_TYPE,
+	OBJECT_USER_MAPPING,
 	OBJECT_VIEW
 } ObjectType;
 
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
index fa9cc59..152bdbb 100644
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -47,6 +47,7 @@ extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod);
 
 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)
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index fb1b4a4..c4c8473 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -642,8 +642,12 @@ extern Datum text_regclass(PG_FUNCTION_ARGS);
 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);
-- 
1.9.1

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