From 70607910c2eeffba3d90c39e9b39ab873822d541 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Mon, 31 Aug 2020 16:47:25 +0900
Subject: [PATCH v2 2/2] Switch to multi-insert dependencies for many code
 paths

This makes use of the new APIs to insert dependencies in groups, instead
of doing the operation one-by-one.  Using the current layer of routines
available, only dependencies of the same type can be grouped, which is
what this patch achieves.
---
 src/backend/catalog/heap.c                 | 59 +++++++-------
 src/backend/catalog/index.c                | 21 ++++-
 src/backend/catalog/pg_aggregate.c         | 23 +++---
 src/backend/catalog/pg_cast.c              | 28 ++++---
 src/backend/catalog/pg_constraint.c        | 34 +++++---
 src/backend/catalog/pg_operator.c          | 20 +++--
 src/backend/catalog/pg_proc.c              | 30 +++++---
 src/backend/catalog/pg_range.c             | 39 ++++------
 src/backend/catalog/pg_type.c              | 62 ++++++++-------
 src/backend/commands/functioncmds.c        | 34 ++++----
 src/backend/commands/proclang.c            | 24 +++---
 src/backend/commands/tsearchcmds.c         | 90 +++++++++++-----------
 src/test/regress/expected/create_index.out |  6 +-
 13 files changed, 250 insertions(+), 220 deletions(-)

diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 9d3ebd93ad..3e221e9a8b 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1428,15 +1428,9 @@ heap_create_with_catalog(const char *relname,
 	{
 		ObjectAddress myself,
 					referenced;
+		ObjectAddresses *addrs;
 
-		myself.classId = RelationRelationId;
-		myself.objectId = relid;
-		myself.objectSubId = 0;
-
-		referenced.classId = NamespaceRelationId;
-		referenced.objectId = relnamespace;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		ObjectAddressSet(myself, RelationRelationId, relid);
 
 		recordDependencyOnOwner(RelationRelationId, relid, ownerid);
 
@@ -1444,12 +1438,15 @@ heap_create_with_catalog(const char *relname,
 
 		recordDependencyOnCurrentExtension(&myself, false);
 
+		addrs = new_object_addresses();
+
+		ObjectAddressSet(referenced, NamespaceRelationId, relnamespace);
+		add_exact_object_address(&referenced, addrs);
+
 		if (reloftypeid)
 		{
-			referenced.classId = TypeRelationId;
-			referenced.objectId = reloftypeid;
-			referenced.objectSubId = 0;
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+			ObjectAddressSet(referenced, TypeRelationId, reloftypeid);
+			add_exact_object_address(&referenced, addrs);
 		}
 
 		/*
@@ -1462,11 +1459,12 @@ heap_create_with_catalog(const char *relname,
 		if (relkind == RELKIND_RELATION ||
 			relkind == RELKIND_MATVIEW)
 		{
-			referenced.classId = AccessMethodRelationId;
-			referenced.objectId = accessmtd;
-			referenced.objectSubId = 0;
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+			ObjectAddressSet(referenced, AccessMethodRelationId, accessmtd);
+			add_exact_object_address(&referenced, addrs);
 		}
+
+		record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+		free_object_addresses(addrs);
 	}
 
 	/* Post creation hook for new relation */
@@ -3574,6 +3572,7 @@ StorePartitionKey(Relation rel,
 	bool		nulls[Natts_pg_partitioned_table];
 	ObjectAddress myself;
 	ObjectAddress referenced;
+	ObjectAddresses *addrs;
 
 	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
 
@@ -3617,31 +3616,27 @@ StorePartitionKey(Relation rel,
 	table_close(pg_partitioned_table, RowExclusiveLock);
 
 	/* Mark this relation as dependent on a few things as follows */
-	myself.classId = RelationRelationId;
-	myself.objectId = RelationGetRelid(rel);
-	myself.objectSubId = 0;
+	addrs = new_object_addresses();
+	ObjectAddressSet(myself, RelationRelationId, RelationGetRelid(rel));
 
 	/* Operator class and collation per key column */
 	for (i = 0; i < partnatts; i++)
 	{
-		referenced.classId = OperatorClassRelationId;
-		referenced.objectId = partopclass[i];
-		referenced.objectSubId = 0;
-
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		ObjectAddressSet(referenced, OperatorClassRelationId, partopclass[i]);
+		add_exact_object_address(&referenced, addrs);
 
 		/* The default collation is pinned, so don't bother recording it */
 		if (OidIsValid(partcollation[i]) &&
 			partcollation[i] != DEFAULT_COLLATION_OID)
 		{
-			referenced.classId = CollationRelationId;
-			referenced.objectId = partcollation[i];
-			referenced.objectSubId = 0;
-
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+			ObjectAddressSet(referenced, CollationRelationId, partcollation[i]);
+			add_exact_object_address(&referenced, addrs);
 		}
 	}
 
+	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+	free_object_addresses(addrs);
+
 	/*
 	 * The partitioning columns are made internally dependent on the table,
 	 * because we cannot drop any of them without dropping the whole table.
@@ -3653,10 +3648,8 @@ StorePartitionKey(Relation rel,
 		if (partattrs[i] == 0)
 			continue;			/* ignore expressions here */
 
-		referenced.classId = RelationRelationId;
-		referenced.objectId = RelationGetRelid(rel);
-		referenced.objectSubId = partattrs[i];
-
+		ObjectAddressSubSet(referenced, RelationRelationId,
+							RelationGetRelid(rel), partattrs[i]);
 		recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
 	}
 
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index d0ec9a4b9c..8146a7d22b 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1018,6 +1018,7 @@ index_create(Relation heapRelation,
 	{
 		ObjectAddress myself,
 					referenced;
+		ObjectAddresses *addrs;
 
 		ObjectAddressSet(myself, RelationRelationId, indexRelationId);
 
@@ -1054,6 +1055,8 @@ index_create(Relation heapRelation,
 		{
 			bool		have_simple_col = false;
 
+			addrs = new_object_addresses();
+
 			/* Create auto dependencies on simply-referenced columns */
 			for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
 			{
@@ -1062,7 +1065,7 @@ index_create(Relation heapRelation,
 					ObjectAddressSubSet(referenced, RelationRelationId,
 										heapRelationId,
 										indexInfo->ii_IndexAttrNumbers[i]);
-					recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+					add_exact_object_address(&referenced, addrs);
 					have_simple_col = true;
 				}
 			}
@@ -1077,8 +1080,11 @@ index_create(Relation heapRelation,
 			{
 				ObjectAddressSet(referenced, RelationRelationId,
 								 heapRelationId);
-				recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+				add_exact_object_address(&referenced, addrs);
 			}
+
+			record_object_address_dependencies(&myself, addrs, DEPENDENCY_AUTO);
+			free_object_addresses(addrs);
 		}
 
 		/*
@@ -1096,7 +1102,11 @@ index_create(Relation heapRelation,
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
 		}
 
+		/* placeholder for normal dependencies */
+		addrs = new_object_addresses();
+
 		/* Store dependency on collations */
+
 		/* The default collation is pinned, so don't bother recording it */
 		for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
 		{
@@ -1105,7 +1115,7 @@ index_create(Relation heapRelation,
 			{
 				ObjectAddressSet(referenced, CollationRelationId,
 								 collationObjectId[i]);
-				recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+				add_exact_object_address(&referenced, addrs);
 			}
 		}
 
@@ -1113,9 +1123,12 @@ index_create(Relation heapRelation,
 		for (i = 0; i < indexInfo->ii_NumIndexKeyAttrs; i++)
 		{
 			ObjectAddressSet(referenced, OperatorClassRelationId, classObjectId[i]);
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+			add_exact_object_address(&referenced, addrs);
 		}
 
+		record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+		free_object_addresses(addrs);
+
 		/* Store dependencies on anything mentioned in index expressions */
 		if (indexInfo->ii_Expressions)
 		{
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 89007ad1ed..a0554f0d79 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -105,6 +105,7 @@ AggregateCreate(const char *aggName,
 	int			i;
 	ObjectAddress myself,
 				referenced;
+	ObjectAddresses *addrs;
 	AclResult	aclresult;
 
 	/* sanity checks (caller should have caught these) */
@@ -741,66 +742,70 @@ AggregateCreate(const char *aggName,
 	 * way.
 	 */
 
+	addrs = new_object_addresses();
+
 	/* Depends on transition function */
 	ObjectAddressSet(referenced, ProcedureRelationId, transfn);
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	add_exact_object_address(&referenced, addrs);
 
 	/* Depends on final function, if any */
 	if (OidIsValid(finalfn))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, finalfn);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* Depends on combine function, if any */
 	if (OidIsValid(combinefn))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, combinefn);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* Depends on serialization function, if any */
 	if (OidIsValid(serialfn))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, serialfn);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* Depends on deserialization function, if any */
 	if (OidIsValid(deserialfn))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, deserialfn);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* Depends on forward transition function, if any */
 	if (OidIsValid(mtransfn))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, mtransfn);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* Depends on inverse transition function, if any */
 	if (OidIsValid(minvtransfn))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, minvtransfn);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* Depends on final function, if any */
 	if (OidIsValid(mfinalfn))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, mfinalfn);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* Depends on sort operator, if any */
 	if (OidIsValid(sortop))
 	{
 		ObjectAddressSet(referenced, OperatorRelationId, sortop);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
+	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+	free_object_addresses(addrs);
 	return myself;
 }
 
diff --git a/src/backend/catalog/pg_cast.c b/src/backend/catalog/pg_cast.c
index 5ea2b82b08..c03e82d74f 100644
--- a/src/backend/catalog/pg_cast.c
+++ b/src/backend/catalog/pg_cast.c
@@ -50,6 +50,7 @@ CastCreate(Oid sourcetypeid, Oid targettypeid, Oid funcid, char castcontext,
 	bool		nulls[Natts_pg_cast];
 	ObjectAddress myself,
 				referenced;
+	ObjectAddresses *addrs;
 
 	relation = table_open(CastRelationId, RowExclusiveLock);
 
@@ -83,32 +84,29 @@ CastCreate(Oid sourcetypeid, Oid targettypeid, Oid funcid, char castcontext,
 
 	CatalogTupleInsert(relation, tuple);
 
+	addrs = new_object_addresses();
+
 	/* make dependency entries */
-	myself.classId = CastRelationId;
-	myself.objectId = castid;
-	myself.objectSubId = 0;
+	ObjectAddressSet(myself, CastRelationId, castid);
 
 	/* dependency on source type */
-	referenced.classId = TypeRelationId;
-	referenced.objectId = sourcetypeid;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, behavior);
+	ObjectAddressSet(referenced, TypeRelationId, sourcetypeid);
+	add_exact_object_address(&referenced, addrs);
 
 	/* dependency on target type */
-	referenced.classId = TypeRelationId;
-	referenced.objectId = targettypeid;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, behavior);
+	ObjectAddressSet(referenced, TypeRelationId, targettypeid);
+	add_exact_object_address(&referenced, addrs);
 
 	/* dependency on function */
 	if (OidIsValid(funcid))
 	{
-		referenced.classId = ProcedureRelationId;
-		referenced.objectId = funcid;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, behavior);
+		ObjectAddressSet(referenced, ProcedureRelationId, funcid);
+		add_exact_object_address(&referenced, addrs);
 	}
 
+	record_object_address_dependencies(&myself, addrs, behavior);
+	free_object_addresses(addrs);
+
 	/* dependency on extension */
 	recordDependencyOnCurrentExtension(&myself, false);
 
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 6a6b2cb8c0..8764e6529d 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -91,6 +91,8 @@ CreateConstraintEntry(const char *constraintName,
 	NameData	cname;
 	int			i;
 	ObjectAddress conobject;
+	ObjectAddresses *addrs_auto;
+	ObjectAddresses *addrs_normal;
 
 	conDesc = table_open(ConstraintRelationId, RowExclusiveLock);
 
@@ -227,6 +229,9 @@ CreateConstraintEntry(const char *constraintName,
 
 	table_close(conDesc, RowExclusiveLock);
 
+	/* Handle set of auto dependencies */
+	addrs_auto = new_object_addresses();
+
 	if (OidIsValid(relId))
 	{
 		/*
@@ -241,13 +246,13 @@ CreateConstraintEntry(const char *constraintName,
 			{
 				ObjectAddressSubSet(relobject, RelationRelationId, relId,
 									constraintKey[i]);
-				recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
+				add_exact_object_address(&relobject, addrs_auto);
 			}
 		}
 		else
 		{
 			ObjectAddressSet(relobject, RelationRelationId, relId);
-			recordDependencyOn(&conobject, &relobject, DEPENDENCY_AUTO);
+			add_exact_object_address(&relobject, addrs_auto);
 		}
 	}
 
@@ -259,9 +264,16 @@ CreateConstraintEntry(const char *constraintName,
 		ObjectAddress domobject;
 
 		ObjectAddressSet(domobject, TypeRelationId, domainId);
-		recordDependencyOn(&conobject, &domobject, DEPENDENCY_AUTO);
+		add_exact_object_address(&domobject, addrs_auto);
 	}
 
+	record_object_address_dependencies(&conobject, addrs_auto,
+									   DEPENDENCY_AUTO);
+	free_object_addresses(addrs_auto);
+
+	/* Handle set if normal dependencies */
+	addrs_normal = new_object_addresses();
+
 	if (OidIsValid(foreignRelId))
 	{
 		/*
@@ -276,13 +288,13 @@ CreateConstraintEntry(const char *constraintName,
 			{
 				ObjectAddressSubSet(relobject, RelationRelationId,
 									foreignRelId, foreignKey[i]);
-				recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
+				add_exact_object_address(&relobject, addrs_normal);
 			}
 		}
 		else
 		{
 			ObjectAddressSet(relobject, RelationRelationId, foreignRelId);
-			recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
+			add_exact_object_address(&relobject, addrs_normal);
 		}
 	}
 
@@ -297,7 +309,7 @@ CreateConstraintEntry(const char *constraintName,
 		ObjectAddress relobject;
 
 		ObjectAddressSet(relobject, RelationRelationId, indexRelId);
-		recordDependencyOn(&conobject, &relobject, DEPENDENCY_NORMAL);
+		add_exact_object_address(&relobject, addrs_normal);
 	}
 
 	if (foreignNKeys > 0)
@@ -316,20 +328,24 @@ CreateConstraintEntry(const char *constraintName,
 		for (i = 0; i < foreignNKeys; i++)
 		{
 			oprobject.objectId = pfEqOp[i];
-			recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
+			add_exact_object_address(&oprobject, addrs_normal);
 			if (ppEqOp[i] != pfEqOp[i])
 			{
 				oprobject.objectId = ppEqOp[i];
-				recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
+				add_exact_object_address(&oprobject, addrs_normal);
 			}
 			if (ffEqOp[i] != pfEqOp[i])
 			{
 				oprobject.objectId = ffEqOp[i];
-				recordDependencyOn(&conobject, &oprobject, DEPENDENCY_NORMAL);
+				add_exact_object_address(&oprobject, addrs_normal);
 			}
 		}
 	}
 
+	record_object_address_dependencies(&conobject, addrs_normal,
+									   DEPENDENCY_NORMAL);
+	free_object_addresses(addrs_normal);
+
 	/*
 	 * We don't bother to register dependencies on the exclusion operators of
 	 * an exclusion constraint.  We assume they are members of the opclass
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 65a36be5ee..f7c07c9b5b 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -775,6 +775,7 @@ makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
 	Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
 	ObjectAddress myself,
 				referenced;
+	ObjectAddresses *addrs;
 
 	ObjectAddressSet(myself, OperatorRelationId, oper->oid);
 
@@ -788,32 +789,34 @@ makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
 		deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
 	}
 
+	addrs = new_object_addresses();
+
 	/* Dependency on namespace */
 	if (OidIsValid(oper->oprnamespace))
 	{
 		ObjectAddressSet(referenced, NamespaceRelationId, oper->oprnamespace);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* Dependency on left type */
 	if (OidIsValid(oper->oprleft))
 	{
 		ObjectAddressSet(referenced, TypeRelationId, oper->oprleft);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* Dependency on right type */
 	if (OidIsValid(oper->oprright))
 	{
 		ObjectAddressSet(referenced, TypeRelationId, oper->oprright);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* Dependency on result type */
 	if (OidIsValid(oper->oprresult))
 	{
 		ObjectAddressSet(referenced, TypeRelationId, oper->oprresult);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/*
@@ -829,23 +832,26 @@ makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
 	if (OidIsValid(oper->oprcode))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, oper->oprcode);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* Dependency on restriction selectivity function */
 	if (OidIsValid(oper->oprrest))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, oper->oprrest);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* Dependency on join selectivity function */
 	if (OidIsValid(oper->oprjoin))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, oper->oprjoin);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
+	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+	free_object_addresses(addrs);
+
 	/* Dependency on owner */
 	recordDependencyOnOwner(OperatorRelationId, oper->oid,
 							oper->oprowner);
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index a28ab74d60..40d65dc6ba 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -114,6 +114,7 @@ ProcedureCreate(const char *procedureName,
 	char	   *detailmsg;
 	int			i;
 	Oid			trfid;
+	ObjectAddresses *addrs;
 
 	/*
 	 * sanity checks
@@ -585,53 +586,58 @@ ProcedureCreate(const char *procedureName,
 	if (is_update)
 		deleteDependencyRecordsFor(ProcedureRelationId, retval, true);
 
+	addrs = new_object_addresses();
+
 	ObjectAddressSet(myself, ProcedureRelationId, retval);
 
 	/* dependency on namespace */
 	ObjectAddressSet(referenced, NamespaceRelationId, procNamespace);
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	add_exact_object_address(&referenced, addrs);
 
 	/* dependency on implementation language */
 	ObjectAddressSet(referenced, LanguageRelationId, languageObjectId);
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	add_exact_object_address(&referenced, addrs);
 
 	/* dependency on return type */
 	ObjectAddressSet(referenced, TypeRelationId, returnType);
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	add_exact_object_address(&referenced, addrs);
 
 	/* dependency on transform used by return type, if any */
 	if ((trfid = get_transform_oid(returnType, languageObjectId, true)))
 	{
 		ObjectAddressSet(referenced, TransformRelationId, trfid);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* dependency on parameter types */
 	for (i = 0; i < allParamCount; i++)
 	{
 		ObjectAddressSet(referenced, TypeRelationId, allParams[i]);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 
 		/* dependency on transform used by parameter type, if any */
 		if ((trfid = get_transform_oid(allParams[i], languageObjectId, true)))
 		{
 			ObjectAddressSet(referenced, TransformRelationId, trfid);
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+			add_exact_object_address(&referenced, addrs);
 		}
 	}
 
-	/* dependency on parameter default expressions */
-	if (parameterDefaults)
-		recordDependencyOnExpr(&myself, (Node *) parameterDefaults,
-							   NIL, DEPENDENCY_NORMAL);
-
 	/* dependency on support function, if any */
 	if (OidIsValid(prosupport))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, prosupport);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
+	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+	free_object_addresses(addrs);
+
+	/* dependency on parameter default expressions */
+	if (parameterDefaults)
+		recordDependencyOnExpr(&myself, (Node *) parameterDefaults,
+							   NIL, DEPENDENCY_NORMAL);
+
 	/* dependency on owner */
 	if (!is_update)
 		recordDependencyOnOwner(ProcedureRelationId, retval, proowner);
diff --git a/src/backend/catalog/pg_range.c b/src/backend/catalog/pg_range.c
index b5bc36c2bd..a606d8c3ad 100644
--- a/src/backend/catalog/pg_range.c
+++ b/src/backend/catalog/pg_range.c
@@ -43,6 +43,7 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation,
 	HeapTuple	tup;
 	ObjectAddress myself;
 	ObjectAddress referenced;
+	ObjectAddresses *addrs;
 
 	pg_range = table_open(RangeRelationId, RowExclusiveLock);
 
@@ -61,45 +62,37 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation,
 	heap_freetuple(tup);
 
 	/* record type's dependencies on range-related items */
+	addrs = new_object_addresses();
 
-	myself.classId = TypeRelationId;
-	myself.objectId = rangeTypeOid;
-	myself.objectSubId = 0;
+	ObjectAddressSet(myself, TypeRelationId, rangeTypeOid);
 
-	referenced.classId = TypeRelationId;
-	referenced.objectId = rangeSubType;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	ObjectAddressSet(referenced, TypeRelationId, rangeSubType);
+	add_exact_object_address(&referenced, addrs);
 
-	referenced.classId = OperatorClassRelationId;
-	referenced.objectId = rangeSubOpclass;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	ObjectAddressSet(referenced, OperatorClassRelationId, rangeSubOpclass);
+	add_exact_object_address(&referenced, addrs);
 
 	if (OidIsValid(rangeCollation))
 	{
-		referenced.classId = CollationRelationId;
-		referenced.objectId = rangeCollation;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		ObjectAddressSet(referenced, CollationRelationId, rangeCollation);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	if (OidIsValid(rangeCanonical))
 	{
-		referenced.classId = ProcedureRelationId;
-		referenced.objectId = rangeCanonical;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		ObjectAddressSet(referenced, ProcedureRelationId, rangeCanonical);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	if (OidIsValid(rangeSubDiff))
 	{
-		referenced.classId = ProcedureRelationId;
-		referenced.objectId = rangeSubDiff;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		ObjectAddressSet(referenced, ProcedureRelationId, rangeSubDiff);
+		add_exact_object_address(&referenced, addrs);
 	}
 
+	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+	free_object_addresses(addrs);
+
 	table_close(pg_range, RowExclusiveLock);
 }
 
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 79ffe317dd..ba83efb505 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -554,6 +554,7 @@ GenerateTypeDependencies(HeapTuple typeTuple,
 	bool		isNull;
 	ObjectAddress myself,
 				referenced;
+	ObjectAddresses *addrs_normal;
 
 	/* Extract defaultExpr if caller didn't pass it */
 	if (defaultExpr == NULL)
@@ -587,6 +588,10 @@ GenerateTypeDependencies(HeapTuple typeTuple,
 	 * Skip these for a dependent type, since it will have such dependencies
 	 * indirectly through its depended-on type or relation.
 	 */
+
+	/* placeholder for all normal dependencies */
+	addrs_normal = new_object_addresses();
+
 	if (!isDependentType)
 	{
 		ObjectAddressSet(referenced, NamespaceRelationId,
@@ -606,45 +611,68 @@ GenerateTypeDependencies(HeapTuple typeTuple,
 	if (OidIsValid(typeForm->typinput))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typinput);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs_normal);
 	}
 
 	if (OidIsValid(typeForm->typoutput))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typoutput);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs_normal);
 	}
 
 	if (OidIsValid(typeForm->typreceive))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typreceive);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs_normal);
 	}
 
 	if (OidIsValid(typeForm->typsend))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typsend);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs_normal);
 	}
 
 	if (OidIsValid(typeForm->typmodin))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodin);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs_normal);
 	}
 
 	if (OidIsValid(typeForm->typmodout))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typmodout);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs_normal);
 	}
 
 	if (OidIsValid(typeForm->typanalyze))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, typeForm->typanalyze);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs_normal);
 	}
 
+	/* Normal dependency from a domain to its base type. */
+	if (OidIsValid(typeForm->typbasetype))
+	{
+		ObjectAddressSet(referenced, TypeRelationId, typeForm->typbasetype);
+		add_exact_object_address(&referenced, addrs_normal);
+	}
+
+	/* Normal dependency from a domain to its collation. */
+	/* We know the default collation is pinned, so don't bother recording it */
+	if (OidIsValid(typeForm->typcollation) &&
+		typeForm->typcollation != DEFAULT_COLLATION_OID)
+	{
+		ObjectAddressSet(referenced, CollationRelationId, typeForm->typcollation);
+		add_exact_object_address(&referenced, addrs_normal);
+	}
+
+	record_object_address_dependencies(&myself, addrs_normal, DEPENDENCY_NORMAL);
+	free_object_addresses(addrs_normal);
+
+	/* Normal dependency on the default expression. */
+	if (defaultExpr)
+		recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
+
 	/*
 	 * If the type is a rowtype for a relation, mark it as internally
 	 * dependent on the relation, *unless* it is a stand-alone composite type
@@ -675,26 +703,6 @@ GenerateTypeDependencies(HeapTuple typeTuple,
 		recordDependencyOn(&myself, &referenced,
 						   isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
 	}
-
-	/* Normal dependency from a domain to its base type. */
-	if (OidIsValid(typeForm->typbasetype))
-	{
-		ObjectAddressSet(referenced, TypeRelationId, typeForm->typbasetype);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-	}
-
-	/* Normal dependency from a domain to its collation. */
-	/* We know the default collation is pinned, so don't bother recording it */
-	if (OidIsValid(typeForm->typcollation) &&
-		typeForm->typcollation != DEFAULT_COLLATION_OID)
-	{
-		ObjectAddressSet(referenced, CollationRelationId, typeForm->typcollation);
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-	}
-
-	/* Normal dependency on the default expression. */
-	if (defaultExpr)
-		recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
 }
 
 /*
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 1b5bdcec8b..e236581a8e 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1696,6 +1696,7 @@ CreateTransform(CreateTransformStmt *stmt)
 	Relation	relation;
 	ObjectAddress myself,
 				referenced;
+	ObjectAddresses *addrs;
 	bool		is_replace;
 
 	/*
@@ -1836,39 +1837,34 @@ CreateTransform(CreateTransformStmt *stmt)
 	if (is_replace)
 		deleteDependencyRecordsFor(TransformRelationId, transformid, true);
 
+	addrs = new_object_addresses();
+
 	/* make dependency entries */
-	myself.classId = TransformRelationId;
-	myself.objectId = transformid;
-	myself.objectSubId = 0;
+	ObjectAddressSet(myself, TransformRelationId, transformid);
 
 	/* dependency on language */
-	referenced.classId = LanguageRelationId;
-	referenced.objectId = langid;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	ObjectAddressSet(referenced, LanguageRelationId, langid);
+	add_exact_object_address(&referenced, addrs);
 
 	/* dependency on type */
-	referenced.classId = TypeRelationId;
-	referenced.objectId = typeid;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	ObjectAddressSet(referenced, TypeRelationId, typeid);
+	add_exact_object_address(&referenced, addrs);
 
 	/* dependencies on functions */
 	if (OidIsValid(fromsqlfuncid))
 	{
-		referenced.classId = ProcedureRelationId;
-		referenced.objectId = fromsqlfuncid;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		ObjectAddressSet(referenced, ProcedureRelationId, fromsqlfuncid);
+		add_exact_object_address(&referenced, addrs);
 	}
 	if (OidIsValid(tosqlfuncid))
 	{
-		referenced.classId = ProcedureRelationId;
-		referenced.objectId = tosqlfuncid;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		ObjectAddressSet(referenced, ProcedureRelationId, tosqlfuncid);
+		add_exact_object_address(&referenced, addrs);
 	}
 
+	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+	free_object_addresses(addrs);
+
 	/* dependency on extension */
 	recordDependencyOnCurrentExtension(&myself, is_replace);
 
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 14153426bd..8ef60374f5 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -57,6 +57,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 	bool		is_update;
 	ObjectAddress myself,
 				referenced;
+	ObjectAddresses *addrs;
 
 	/*
 	 * Check permission
@@ -186,30 +187,29 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 	/* dependency on extension */
 	recordDependencyOnCurrentExtension(&myself, is_update);
 
+	addrs = new_object_addresses();
+
 	/* dependency on the PL handler function */
-	referenced.classId = ProcedureRelationId;
-	referenced.objectId = handlerOid;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	ObjectAddressSet(referenced, ProcedureRelationId, handlerOid);
+	add_exact_object_address(&referenced, addrs);
 
 	/* dependency on the inline handler function, if any */
 	if (OidIsValid(inlineOid))
 	{
-		referenced.classId = ProcedureRelationId;
-		referenced.objectId = inlineOid;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		ObjectAddressSet(referenced, ProcedureRelationId, inlineOid);
+		add_exact_object_address(&referenced, addrs);
 	}
 
 	/* dependency on the validator function, if any */
 	if (OidIsValid(valOid))
 	{
-		referenced.classId = ProcedureRelationId;
-		referenced.objectId = valOid;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		ObjectAddressSet(referenced, ProcedureRelationId, valOid);
+		add_exact_object_address(&referenced, addrs);
 	}
 
+	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+	free_object_addresses(addrs);
+
 	/* Post creation hook for new procedural language */
 	InvokeObjectPostCreateHook(LanguageRelationId, myself.objectId, 0);
 
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 319a62012e..f5d1d137b8 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -133,42 +133,41 @@ makeParserDependencies(HeapTuple tuple)
 	Form_pg_ts_parser prs = (Form_pg_ts_parser) GETSTRUCT(tuple);
 	ObjectAddress myself,
 				referenced;
+	ObjectAddresses *addrs;
 
-	myself.classId = TSParserRelationId;
-	myself.objectId = prs->oid;
-	myself.objectSubId = 0;
-
-	/* dependency on namespace */
-	referenced.classId = NamespaceRelationId;
-	referenced.objectId = prs->prsnamespace;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	ObjectAddressSet(myself, TSParserRelationId, prs->oid);
 
 	/* dependency on extension */
 	recordDependencyOnCurrentExtension(&myself, false);
 
-	/* dependencies on functions */
-	referenced.classId = ProcedureRelationId;
-	referenced.objectSubId = 0;
+	addrs = new_object_addresses();
 
-	referenced.objectId = prs->prsstart;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	/* dependency on namespace */
+	ObjectAddressSet(referenced, NamespaceRelationId, prs->prsnamespace);
+	add_exact_object_address(&referenced, addrs);
+
+	/* dependencies on functions */
+	ObjectAddressSet(referenced, ProcedureRelationId, prs->prsstart);
+	add_exact_object_address(&referenced, addrs);
 
 	referenced.objectId = prs->prstoken;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	add_exact_object_address(&referenced, addrs);
 
 	referenced.objectId = prs->prsend;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	add_exact_object_address(&referenced, addrs);
 
 	referenced.objectId = prs->prslextype;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	add_exact_object_address(&referenced, addrs);
 
 	if (OidIsValid(prs->prsheadline))
 	{
 		referenced.objectId = prs->prsheadline;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
+	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+	free_object_addresses(addrs);
+
 	return myself;
 }
 
@@ -304,16 +303,9 @@ makeDictionaryDependencies(HeapTuple tuple)
 	Form_pg_ts_dict dict = (Form_pg_ts_dict) GETSTRUCT(tuple);
 	ObjectAddress myself,
 				referenced;
+	ObjectAddresses *addrs;
 
-	myself.classId = TSDictionaryRelationId;
-	myself.objectId = dict->oid;
-	myself.objectSubId = 0;
-
-	/* dependency on namespace */
-	referenced.classId = NamespaceRelationId;
-	referenced.objectId = dict->dictnamespace;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	ObjectAddressSet(myself, TSDictionaryRelationId, dict->oid);
 
 	/* dependency on owner */
 	recordDependencyOnOwner(myself.classId, myself.objectId, dict->dictowner);
@@ -321,11 +313,18 @@ makeDictionaryDependencies(HeapTuple tuple)
 	/* dependency on extension */
 	recordDependencyOnCurrentExtension(&myself, false);
 
+	addrs = new_object_addresses();
+
+	/* dependency on namespace */
+	ObjectAddressSet(referenced, NamespaceRelationId, dict->dictnamespace);
+	add_exact_object_address(&referenced, addrs);
+
 	/* dependency on template */
-	referenced.classId = TSTemplateRelationId;
-	referenced.objectId = dict->dicttemplate;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	ObjectAddressSet(referenced, TSTemplateRelationId, dict->dicttemplate);
+	add_exact_object_address(&referenced, addrs);
+
+	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+	free_object_addresses(addrs);
 
 	return myself;
 }
@@ -649,33 +648,32 @@ makeTSTemplateDependencies(HeapTuple tuple)
 	Form_pg_ts_template tmpl = (Form_pg_ts_template) GETSTRUCT(tuple);
 	ObjectAddress myself,
 				referenced;
+	ObjectAddresses *addrs;
 
-	myself.classId = TSTemplateRelationId;
-	myself.objectId = tmpl->oid;
-	myself.objectSubId = 0;
-
-	/* dependency on namespace */
-	referenced.classId = NamespaceRelationId;
-	referenced.objectId = tmpl->tmplnamespace;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	ObjectAddressSet(myself, TSTemplateRelationId, tmpl->oid);
 
 	/* dependency on extension */
 	recordDependencyOnCurrentExtension(&myself, false);
 
-	/* dependencies on functions */
-	referenced.classId = ProcedureRelationId;
-	referenced.objectSubId = 0;
+	addrs = new_object_addresses();
 
-	referenced.objectId = tmpl->tmpllexize;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	/* dependency on namespace */
+	ObjectAddressSet(referenced, NamespaceRelationId, tmpl->tmplnamespace);
+	add_exact_object_address(&referenced, addrs);
+
+	/* dependencies on functions */
+	ObjectAddressSet(referenced, ProcedureRelationId, tmpl->tmpllexize);
+	add_exact_object_address(&referenced, addrs);
 
 	if (OidIsValid(tmpl->tmplinit))
 	{
 		referenced.objectId = tmpl->tmplinit;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		add_exact_object_address(&referenced, addrs);
 	}
 
+	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
+	free_object_addresses(addrs);
+
 	return myself;
 }
 
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index e3e6634d7e..814416d936 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2069,11 +2069,10 @@ WHERE classid = 'pg_class'::regclass AND
  index concur_reindex_ind3                | column c1 of table concur_reindex_tab                      | a
  index concur_reindex_ind3                | table concur_reindex_tab                                   | a
  index concur_reindex_ind4                | column c1 of table concur_reindex_tab                      | a
- index concur_reindex_ind4                | column c1 of table concur_reindex_tab                      | a
  index concur_reindex_ind4                | column c2 of table concur_reindex_tab                      | a
  materialized view concur_reindex_matview | schema public                                              | n
  table concur_reindex_tab                 | schema public                                              | n
-(9 rows)
+(8 rows)
 
 REINDEX INDEX CONCURRENTLY concur_reindex_ind1;
 REINDEX TABLE CONCURRENTLY concur_reindex_tab;
@@ -2097,11 +2096,10 @@ WHERE classid = 'pg_class'::regclass AND
  index concur_reindex_ind3                | column c1 of table concur_reindex_tab                      | a
  index concur_reindex_ind3                | table concur_reindex_tab                                   | a
  index concur_reindex_ind4                | column c1 of table concur_reindex_tab                      | a
- index concur_reindex_ind4                | column c1 of table concur_reindex_tab                      | a
  index concur_reindex_ind4                | column c2 of table concur_reindex_tab                      | a
  materialized view concur_reindex_matview | schema public                                              | n
  table concur_reindex_tab                 | schema public                                              | n
-(9 rows)
+(8 rows)
 
 -- Check that comments are preserved
 CREATE TABLE testcomment (i int);
-- 
2.28.0

