From dc75e3255803617d21c55d77dc218904bd729d81 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Fri, 29 Mar 2024 15:43:26 +0000
Subject: [PATCH v10] Avoid orphaned objects dependencies

It's currently possible to create orphaned objects dependencies, for example:

Scenario 1:

session 1: begin; drop schema schem;
session 2: create a function in the schema schem
session 1: commit;

With the above, the function created in session 2 would be linked to a non
existing schema.

Scenario 2:

session 1: begin; create a function in the schema schem
session 2: drop schema schem;
session 1: commit;

With the above, the function created in session 1 would be linked to a non
existing schema.

To avoid those scenarios, a new lock (that conflicts with a lock taken by DROP)
has been put in place before the dependencies are being recorded. With this in
place, the drop schema in scenario 2 would be locked.

Also, after the new lock attempt, the patch checks that the object still exists:
with this in place session 2 in scenario 1 would be locked and would report an
error once session 1 committs (that would not be the case should session 1 abort
the transaction).

If the object is dropped before the new lock attempt is triggered then the patch
would also report an error (but with less details).

The patch adds a few tests for some dependency cases (that would currently produce
orphaned objects):

- schema and function (as the above scenarios)
- alter a dependency (function and schema)
- function and arg type
- function and return type
- function and function
- domain and domain
- table and type
- server and foreign data wrapper
---
 src/backend/catalog/aclchk.c                  |   1 +
 src/backend/catalog/dependency.c              | 109 ++++++++++++++-
 src/backend/catalog/heap.c                    |   8 ++
 src/backend/catalog/index.c                   |  16 +++
 src/backend/catalog/objectaddress.c           |  57 ++++++++
 src/backend/catalog/pg_aggregate.c            |   9 ++
 src/backend/catalog/pg_attrdef.c              |   1 +
 src/backend/catalog/pg_cast.c                 |   5 +
 src/backend/catalog/pg_collation.c            |   1 +
 src/backend/catalog/pg_constraint.c           |  11 ++
 src/backend/catalog/pg_conversion.c           |   2 +
 src/backend/catalog/pg_depend.c               |  27 +++-
 src/backend/catalog/pg_operator.c             |  19 +++
 src/backend/catalog/pg_proc.c                 |  17 ++-
 src/backend/catalog/pg_publication.c          |   5 +
 src/backend/catalog/pg_range.c                |   6 +
 src/backend/catalog/pg_type.c                 |  33 +++++
 src/backend/catalog/toasting.c                |   1 +
 src/backend/commands/alter.c                  |   4 +
 src/backend/commands/amcmds.c                 |   1 +
 src/backend/commands/cluster.c                |   5 +
 src/backend/commands/event_trigger.c          |   1 +
 src/backend/commands/extension.c              |   5 +
 src/backend/commands/foreigncmds.c            |   7 +
 src/backend/commands/functioncmds.c           |   6 +
 src/backend/commands/indexcmds.c              |   2 +
 src/backend/commands/opclasscmds.c            |  18 +++
 src/backend/commands/operatorcmds.c           |  30 ++++
 src/backend/commands/policy.c                 |   2 +
 src/backend/commands/proclang.c               |   3 +
 src/backend/commands/sequence.c               |   1 +
 src/backend/commands/statscmds.c              |   3 +
 src/backend/commands/tablecmds.c              |  32 +++--
 src/backend/commands/trigger.c                |  18 ++-
 src/backend/commands/tsearchcmds.c            |  81 +++++++----
 src/backend/commands/typecmds.c               |  84 ++++++++++++
 src/backend/rewrite/rewriteDefine.c           |   1 +
 src/backend/utils/errcodes.txt                |   1 +
 src/include/catalog/dependency.h              |   7 +
 src/include/catalog/objectaddress.h           |   1 +
 .../expected/test_dependencies_locks.out      | 129 ++++++++++++++++++
 src/test/isolation/isolation_schedule         |   1 +
 .../specs/test_dependencies_locks.spec        |  89 ++++++++++++
 43 files changed, 813 insertions(+), 47 deletions(-)
  31.4% src/backend/catalog/
  36.4% src/backend/commands/
  18.5% src/test/isolation/expected/
  11.5% src/test/isolation/specs/

diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 143876b77f..5a614f25ff 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -1413,6 +1413,7 @@ SetDefaultACL(InternalDefaultACL *iacls)
 				referenced.objectId = iacls->nspid;
 				referenced.objectSubId = 0;
 
+				LockNotPinnedObject(NamespaceRelationId, iacls->nspid);
 				recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 			}
 		}
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 0489cbabcb..abf8b92a6d 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1519,6 +1519,84 @@ AcquireDeletionLock(const ObjectAddress *object, int flags)
 	}
 }
 
+/*
+ * LockNotPinnedObjectById
+ *
+ * Lock the object that we are about to record a dependency on.
+ * After it's locked, verify that it hasn't been dropped while we
+ * weren't looking.  If the object has been dropped, this function
+ * does not return!
+ */
+void
+LockNotPinnedObjectById(const ObjectAddress *object)
+{
+	char	   *object_description;
+
+	if (isObjectPinned(object))
+		return;
+
+	/*
+	 * Those don't rely on LockDatabaseObject() when being dropped (see
+	 * AcquireDeletionLock()). Also it looks like they can not produce
+	 * orphaned dependent objects when being dropped.
+	 */
+	if (object->classId == RelationRelationId || object->classId == AuthMemRelationId)
+		return;
+
+	object_description = getObjectDescription(object, true);
+
+	/* assume we should lock the whole object not a sub-object */
+	LockDatabaseObject(object->classId, object->objectId, 0, AccessShareLock);
+
+	/* check if object still exists */
+	if (!ObjectByIdExist(object))
+	{
+		if (object_description)
+			ereport(ERROR,
+					(errcode(ERRCODE_DEPENDENT_OBJECTS_DOES_NOT_EXIST),
+					 errmsg("%s does not exist", object_description)));
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_DEPENDENT_OBJECTS_DOES_NOT_EXIST),
+					 errmsg("a dependent object does not exist")));
+	}
+
+	if (object_description)
+		pfree(object_description);
+
+	return;
+}
+
+void
+LockNotPinnedObjectsById(const ObjectAddress *object, int nobject)
+{
+	int			i;
+
+	if (nobject < 0)
+		return;
+
+	for (i = 0; i < nobject; i++, object++)
+		LockNotPinnedObjectById(object);
+
+	return;
+}
+
+
+/*
+ * LockNotPinnedObject
+ *
+ * Lock the object that we are about to record a dependency on.
+ */
+void
+LockNotPinnedObject(Oid classid, Oid objid)
+{
+	ObjectAddress object;
+
+	ObjectAddressSet(object, classid, objid);
+
+	LockNotPinnedObjectById(&object);
+}
+
 /*
  * ReleaseDeletionLock - release an object deletion lock
  *
@@ -1564,13 +1642,8 @@ recordDependencyOnExpr(const ObjectAddress *depender,
 	/* Scan the expression tree for referenceable objects */
 	find_expr_references_walker(expr, &context);
 
-	/* Remove any duplicates */
-	eliminate_duplicate_dependencies(context.addrs);
-
-	/* And record 'em */
-	recordMultipleDependencies(depender,
-							   context.addrs->refs, context.addrs->numrefs,
-							   behavior);
+	/* Record all of them (this includes duplicate elimination) */
+	lock_record_object_address_dependencies(depender, context.addrs, behavior);
 
 	free_object_addresses(context.addrs);
 }
@@ -1654,14 +1727,19 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
 
 		/* Record the self-dependencies with the appropriate direction */
 		if (!reverse_self)
+		{
+			LockNotPinnedObjectsById(self_addrs->refs, self_addrs->numrefs);
 			recordMultipleDependencies(depender,
 									   self_addrs->refs, self_addrs->numrefs,
 									   self_behavior);
+		}
 		else
 		{
 			/* Can't use recordMultipleDependencies, so do it the hard way */
 			int			selfref;
 
+			LockNotPinnedObjectById(depender);
+
 			for (selfref = 0; selfref < self_addrs->numrefs; selfref++)
 			{
 				ObjectAddress *thisobj = self_addrs->refs + selfref;
@@ -1674,6 +1752,7 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
 	}
 
 	/* Record the external dependencies */
+	LockNotPinnedObjectsById(context.addrs->refs, context.addrs->numrefs);
 	recordMultipleDependencies(depender,
 							   context.addrs->refs, context.addrs->numrefs,
 							   behavior);
@@ -2734,6 +2813,22 @@ stack_address_present_add_flags(const ObjectAddress *object,
 	return result;
 }
 
+/*
+ * Record multiple dependencies from an ObjectAddresses array and lock the
+ * referenced objects, after first removing any duplicates.
+ */
+void
+lock_record_object_address_dependencies(const ObjectAddress *depender,
+										ObjectAddresses *referenced,
+										DependencyType behavior)
+{
+	eliminate_duplicate_dependencies(referenced);
+	LockNotPinnedObjectsById(referenced->refs, referenced->numrefs);
+	recordMultipleDependencies(depender,
+							   referenced->refs, referenced->numrefs,
+							   behavior);
+}
+
 /*
  * Record multiple dependencies from an ObjectAddresses array, after first
  * removing any duplicates.
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index a122bbffce..72443710d3 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -843,6 +843,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
 		ObjectAddressSubSet(myself, RelationRelationId, new_rel_oid, i + 1);
 		ObjectAddressSet(referenced, TypeRelationId,
 						 tupdesc->attrs[i].atttypid);
+		LockNotPinnedObject(TypeRelationId, tupdesc->attrs[i].atttypid);
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 		/* The default collation is pinned, so don't bother recording it */
@@ -851,6 +852,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
 		{
 			ObjectAddressSet(referenced, CollationRelationId,
 							 tupdesc->attrs[i].attcollation);
+			LockNotPinnedObject(CollationRelationId, tupdesc->attrs[i].attcollation);
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
 	}
@@ -1451,11 +1453,13 @@ heap_create_with_catalog(const char *relname,
 
 		ObjectAddressSet(referenced, NamespaceRelationId, relnamespace);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(NamespaceRelationId, relnamespace);
 
 		if (reloftypeid)
 		{
 			ObjectAddressSet(referenced, TypeRelationId, reloftypeid);
 			add_exact_object_address(&referenced, addrs);
+			LockNotPinnedObject(TypeRelationId, reloftypeid);
 		}
 
 		/*
@@ -1469,6 +1473,7 @@ heap_create_with_catalog(const char *relname,
 		{
 			ObjectAddressSet(referenced, AccessMethodRelationId, accessmtd);
 			add_exact_object_address(&referenced, addrs);
+			LockNotPinnedObject(AccessMethodRelationId, accessmtd);
 		}
 
 		record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
@@ -3383,6 +3388,7 @@ StorePartitionKey(Relation rel,
 	{
 		ObjectAddressSet(referenced, OperatorClassRelationId, partopclass[i]);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(OperatorClassRelationId, partopclass[i]);
 
 		/* The default collation is pinned, so don't bother recording it */
 		if (OidIsValid(partcollation[i]) &&
@@ -3390,6 +3396,7 @@ StorePartitionKey(Relation rel,
 		{
 			ObjectAddressSet(referenced, CollationRelationId, partcollation[i]);
 			add_exact_object_address(&referenced, addrs);
+			LockNotPinnedObject(CollationRelationId, partcollation[i]);
 		}
 	}
 
@@ -3409,6 +3416,7 @@ StorePartitionKey(Relation rel,
 
 		ObjectAddressSubSet(referenced, RelationRelationId,
 							RelationGetRelid(rel), partattrs[i]);
+		/* Do we need a lock on RelationRelationId? */
 		recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
 	}
 
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 55fdde4b24..b89c217a09 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1127,6 +1127,7 @@ index_create(Relation heapRelation,
 										heapRelationId,
 										indexInfo->ii_IndexAttrNumbers[i]);
 					add_exact_object_address(&referenced, addrs);
+					/* XXX Do we need a lock for RelationRelationId? */
 					have_simple_col = true;
 				}
 			}
@@ -1141,6 +1142,7 @@ index_create(Relation heapRelation,
 			{
 				ObjectAddressSet(referenced, RelationRelationId,
 								 heapRelationId);
+				/* XXX Do we need a lock for RelationRelationId? */
 				add_exact_object_address(&referenced, addrs);
 			}
 
@@ -1157,9 +1159,11 @@ index_create(Relation heapRelation,
 		if (OidIsValid(parentIndexRelid))
 		{
 			ObjectAddressSet(referenced, RelationRelationId, parentIndexRelid);
+			/* XXX Do we need a lock for RelationRelationId? */
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
 
 			ObjectAddressSet(referenced, RelationRelationId, heapRelationId);
+			/* XXX Do we need a lock for RelationRelationId? */
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
 		}
 
@@ -1175,6 +1179,7 @@ index_create(Relation heapRelation,
 			{
 				ObjectAddressSet(referenced, CollationRelationId, collationIds[i]);
 				add_exact_object_address(&referenced, addrs);
+				LockNotPinnedObject(CollationRelationId, collationIds[i]);
 			}
 		}
 
@@ -1183,6 +1188,7 @@ index_create(Relation heapRelation,
 		{
 			ObjectAddressSet(referenced, OperatorClassRelationId, opclassIds[i]);
 			add_exact_object_address(&referenced, addrs);
+			LockNotPinnedObject(OperatorClassRelationId, opclassIds[i]);
 		}
 
 		record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
@@ -1987,6 +1993,14 @@ index_constraint_create(Relation heapRelation,
 	 */
 	ObjectAddressSet(myself, ConstraintRelationId, conOid);
 	ObjectAddressSet(idxaddr, RelationRelationId, indexRelationId);
+
+	/*
+	 * CommandCounterIncrement here to ensure the new constraint entry is
+	 * visible when we'll check of object existence when recording the
+	 * dependencies.
+	 */
+	CommandCounterIncrement();
+	LockNotPinnedObject(ConstraintRelationId, conOid);
 	recordDependencyOn(&idxaddr, &myself, DEPENDENCY_INTERNAL);
 
 	/*
@@ -1998,9 +2012,11 @@ index_constraint_create(Relation heapRelation,
 		ObjectAddress referenced;
 
 		ObjectAddressSet(referenced, ConstraintRelationId, parentConstraintId);
+		LockNotPinnedObject(ConstraintRelationId, parentConstraintId);
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
 		ObjectAddressSet(referenced, RelationRelationId,
 						 RelationGetRelid(heapRelation));
+		/* XXX Do we need a lock for RelationRelationId? */
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
 	}
 
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 7b536ac6fd..6d7abd3738 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2590,6 +2590,63 @@ get_object_namespace(const ObjectAddress *address)
 	return oid;
 }
 
+/*
+ * ObjectByIdExist
+ *
+ * Return whether the given object exists.
+ *
+ * Works for most catalogs, if no special processing is needed.
+ */
+bool
+ObjectByIdExist(const ObjectAddress *address)
+{
+	HeapTuple	tuple;
+	int			cache;
+	const ObjectPropertyType *property;
+
+	property = get_object_property_data(address->classId);
+
+	cache = property->oid_catcache_id;
+
+	if (cache >= 0)
+	{
+		/* Fetch tuple from syscache. */
+		tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId));
+
+		if (!HeapTupleIsValid(tuple))
+		{
+			return false;
+		}
+
+		ReleaseSysCache(tuple);
+
+		return true;
+	}
+	else
+	{
+		Relation	rel;
+		ScanKeyData skey[1];
+		SysScanDesc scan;
+
+		rel = table_open(address->classId, AccessShareLock);
+
+		ScanKeyInit(&skey[0],
+					get_object_attnum_oid(address->classId),
+					BTEqualStrategyNumber, F_OIDEQ,
+					ObjectIdGetDatum(address->objectId));
+
+		scan = systable_beginscan(rel, get_object_oid_index(address->classId), true,
+								  NULL, 1, skey);
+
+		/* we expect exactly one match */
+		tuple = systable_getnext(scan);
+		systable_endscan(scan);
+		table_close(rel, AccessShareLock);
+
+		return (HeapTupleIsValid(tuple));
+	}
+}
+
 /*
  * Return ObjectType for the given object type as given by
  * getObjectTypeDescription; if no valid ObjectType code exists, but it's a
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 90fc7db949..a47e3c5507 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -748,12 +748,14 @@ AggregateCreate(const char *aggName,
 	/* Depends on transition function */
 	ObjectAddressSet(referenced, ProcedureRelationId, transfn);
 	add_exact_object_address(&referenced, addrs);
+	LockNotPinnedObject(ProcedureRelationId, transfn);
 
 	/* Depends on final function, if any */
 	if (OidIsValid(finalfn))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, finalfn);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, finalfn);
 	}
 
 	/* Depends on combine function, if any */
@@ -761,6 +763,7 @@ AggregateCreate(const char *aggName,
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, combinefn);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, combinefn);
 	}
 
 	/* Depends on serialization function, if any */
@@ -768,6 +771,7 @@ AggregateCreate(const char *aggName,
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, serialfn);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, serialfn);
 	}
 
 	/* Depends on deserialization function, if any */
@@ -775,6 +779,7 @@ AggregateCreate(const char *aggName,
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, deserialfn);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, deserialfn);
 	}
 
 	/* Depends on forward transition function, if any */
@@ -782,6 +787,7 @@ AggregateCreate(const char *aggName,
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, mtransfn);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, mtransfn);
 	}
 
 	/* Depends on inverse transition function, if any */
@@ -789,6 +795,7 @@ AggregateCreate(const char *aggName,
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, minvtransfn);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, minvtransfn);
 	}
 
 	/* Depends on final function, if any */
@@ -796,6 +803,7 @@ AggregateCreate(const char *aggName,
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, mfinalfn);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, mfinalfn);
 	}
 
 	/* Depends on sort operator, if any */
@@ -803,6 +811,7 @@ AggregateCreate(const char *aggName,
 	{
 		ObjectAddressSet(referenced, OperatorRelationId, sortop);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(OperatorRelationId, sortop);
 	}
 
 	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
diff --git a/src/backend/catalog/pg_attrdef.c b/src/backend/catalog/pg_attrdef.c
index 003ae70b4d..80db2c0c20 100644
--- a/src/backend/catalog/pg_attrdef.c
+++ b/src/backend/catalog/pg_attrdef.c
@@ -178,6 +178,7 @@ StoreAttrDefault(Relation rel, AttrNumber attnum,
 	colobject.objectId = RelationGetRelid(rel);
 	colobject.objectSubId = attnum;
 
+	/* XXX Do we need a lock for RelationRelationId? */
 	recordDependencyOn(&defobject, &colobject,
 					   attgenerated ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
 
diff --git a/src/backend/catalog/pg_cast.c b/src/backend/catalog/pg_cast.c
index 5a5b855d51..d3707e424c 100644
--- a/src/backend/catalog/pg_cast.c
+++ b/src/backend/catalog/pg_cast.c
@@ -97,16 +97,19 @@ CastCreate(Oid sourcetypeid, Oid targettypeid,
 	/* dependency on source type */
 	ObjectAddressSet(referenced, TypeRelationId, sourcetypeid);
 	add_exact_object_address(&referenced, addrs);
+	LockNotPinnedObject(TypeRelationId, sourcetypeid);
 
 	/* dependency on target type */
 	ObjectAddressSet(referenced, TypeRelationId, targettypeid);
 	add_exact_object_address(&referenced, addrs);
+	LockNotPinnedObject(TypeRelationId, targettypeid);
 
 	/* dependency on function */
 	if (OidIsValid(funcid))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, funcid);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, funcid);
 	}
 
 	/* dependencies on casts required for function */
@@ -114,11 +117,13 @@ CastCreate(Oid sourcetypeid, Oid targettypeid,
 	{
 		ObjectAddressSet(referenced, CastRelationId, incastid);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(CastRelationId, incastid);
 	}
 	if (OidIsValid(outcastid))
 	{
 		ObjectAddressSet(referenced, CastRelationId, outcastid);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(CastRelationId, outcastid);
 	}
 
 	record_object_address_dependencies(&myself, addrs, behavior);
diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c
index 7f2f701229..78498b8c20 100644
--- a/src/backend/catalog/pg_collation.c
+++ b/src/backend/catalog/pg_collation.c
@@ -218,6 +218,7 @@ CollationCreate(const char *collname, Oid collnamespace,
 	referenced.classId = NamespaceRelationId;
 	referenced.objectId = collnamespace;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(NamespaceRelationId, collnamespace);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	/* create dependency on owner */
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 3baf9231ed..4afa9a1d69 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -257,12 +257,14 @@ CreateConstraintEntry(const char *constraintName,
 				ObjectAddressSubSet(relobject, RelationRelationId, relId,
 									constraintKey[i]);
 				add_exact_object_address(&relobject, addrs_auto);
+				/* XXX Do we need a lock for RelationRelationId?? */
 			}
 		}
 		else
 		{
 			ObjectAddressSet(relobject, RelationRelationId, relId);
 			add_exact_object_address(&relobject, addrs_auto);
+			/* XXX Do we need a lock for RelationRelationId?? */
 		}
 	}
 
@@ -275,6 +277,7 @@ CreateConstraintEntry(const char *constraintName,
 
 		ObjectAddressSet(domobject, TypeRelationId, domainId);
 		add_exact_object_address(&domobject, addrs_auto);
+		LockNotPinnedObject(TypeRelationId, domainId);
 	}
 
 	record_object_address_dependencies(&conobject, addrs_auto,
@@ -299,12 +302,14 @@ CreateConstraintEntry(const char *constraintName,
 				ObjectAddressSubSet(relobject, RelationRelationId,
 									foreignRelId, foreignKey[i]);
 				add_exact_object_address(&relobject, addrs_normal);
+				/* XXX Do we need a lock for RelationRelationId? */
 			}
 		}
 		else
 		{
 			ObjectAddressSet(relobject, RelationRelationId, foreignRelId);
 			add_exact_object_address(&relobject, addrs_normal);
+			/* XXX Do we need a lock for RelationRelationId? */
 		}
 	}
 
@@ -320,6 +325,7 @@ CreateConstraintEntry(const char *constraintName,
 
 		ObjectAddressSet(relobject, RelationRelationId, indexRelId);
 		add_exact_object_address(&relobject, addrs_normal);
+		/* XXX Do we need a lock for RelationRelationId?? */
 	}
 
 	if (foreignNKeys > 0)
@@ -339,15 +345,18 @@ CreateConstraintEntry(const char *constraintName,
 		{
 			oprobject.objectId = pfEqOp[i];
 			add_exact_object_address(&oprobject, addrs_normal);
+			LockNotPinnedObject(OperatorRelationId, pfEqOp[i]);
 			if (ppEqOp[i] != pfEqOp[i])
 			{
 				oprobject.objectId = ppEqOp[i];
 				add_exact_object_address(&oprobject, addrs_normal);
+				LockNotPinnedObject(OperatorRelationId, ppEqOp[i]);
 			}
 			if (ffEqOp[i] != pfEqOp[i])
 			{
 				oprobject.objectId = ffEqOp[i];
 				add_exact_object_address(&oprobject, addrs_normal);
+				LockNotPinnedObject(OperatorRelationId, ffEqOp[i]);
 			}
 		}
 	}
@@ -858,9 +867,11 @@ ConstraintSetParentConstraint(Oid childConstrId,
 		ObjectAddressSet(depender, ConstraintRelationId, childConstrId);
 
 		ObjectAddressSet(referenced, ConstraintRelationId, parentConstrId);
+		LockNotPinnedObject(ConstraintRelationId, parentConstrId);
 		recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_PRI);
 
 		ObjectAddressSet(referenced, RelationRelationId, childTableId);
+		/* XXX Do we need a lock for RelationRelationId? */
 		recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_SEC);
 	}
 	else
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index 0770878eac..25881654d6 100644
--- a/src/backend/catalog/pg_conversion.c
+++ b/src/backend/catalog/pg_conversion.c
@@ -116,12 +116,14 @@ ConversionCreate(const char *conname, Oid connamespace,
 	referenced.classId = ProcedureRelationId;
 	referenced.objectId = conproc;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(ProcedureRelationId, conproc);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	/* create dependency on namespace */
 	referenced.classId = NamespaceRelationId;
 	referenced.objectId = connamespace;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(NamespaceRelationId, connamespace);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	/* create dependency on owner */
diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
index cfd7ef51df..b97aa2ab91 100644
--- a/src/backend/catalog/pg_depend.c
+++ b/src/backend/catalog/pg_depend.c
@@ -20,21 +20,20 @@
 #include "catalog/catalog.h"
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
+#include "catalog/pg_auth_members.h"
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_depend.h"
 #include "catalog/pg_extension.h"
 #include "catalog/partition.h"
 #include "commands/extension.h"
 #include "miscadmin.h"
+#include "storage/lock.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 #include "utils/rel.h"
 
 
-static bool isObjectPinned(const ObjectAddress *object);
-
-
 /*
  * Record a dependency between 2 objects via their respective objectAddress.
  * The first argument is the dependent object, the second the one it
@@ -100,6 +99,25 @@ recordMultipleDependencies(const ObjectAddress *depender,
 	slot_init_count = 0;
 	for (i = 0; i < nreferenced; i++, referenced++)
 	{
+#ifdef USE_ASSERT_CHECKING
+		LOCKTAG		tag;
+
+		SET_LOCKTAG_OBJECT(tag,
+						   MyDatabaseId,
+						   referenced->classId,
+						   referenced->objectId,
+						   0);
+
+		/*
+		 * Assert the referenced object is locked (see
+		 * LockNotPinnedObjectById()).
+		 */
+		Assert(isObjectPinned(referenced) ||
+			   referenced->classId == RelationRelationId ||
+			   referenced->classId == AuthMemRelationId ||
+			   LockHeldByMe(&tag, AccessShareLock));
+#endif
+
 		/*
 		 * If the referenced object is pinned by the system, there's no real
 		 * need to record dependencies on it.  This saves lots of space in
@@ -239,6 +257,7 @@ recordDependencyOnCurrentExtension(const ObjectAddress *object,
 		extension.objectId = CurrentExtensionObject;
 		extension.objectSubId = 0;
 
+		LockNotPinnedObject(ExtensionRelationId, CurrentExtensionObject);
 		recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION);
 	}
 }
@@ -706,7 +725,7 @@ changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
  * The passed subId, if any, is ignored; we assume that only whole objects
  * are pinned (and that this implies pinning their components).
  */
-static bool
+bool
 isObjectPinned(const ObjectAddress *object)
 {
 	return IsPinnedObject(object->classId, object->objectId);
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 65b45a424a..e8374eec88 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -251,6 +251,16 @@ OperatorShellMake(const char *operatorName,
 	values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
 	values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
 
+	/* Lock dependent objects */
+	if (OidIsValid(operatorNamespace))
+		LockNotPinnedObject(NamespaceRelationId, operatorNamespace);
+
+	if (OidIsValid(leftTypeId))
+		LockNotPinnedObject(TypeRelationId, leftTypeId);
+
+	if (OidIsValid(rightTypeId))
+		LockNotPinnedObject(TypeRelationId, rightTypeId);
+
 	/*
 	 * create a new operator tuple
 	 */
@@ -513,6 +523,15 @@ OperatorCreate(const char *operatorName,
 		CatalogTupleInsert(pg_operator_desc, tup);
 	}
 
+	/* Lock dependent objects */
+	LockNotPinnedObject(NamespaceRelationId, operatorNamespace);
+	LockNotPinnedObject(TypeRelationId, leftTypeId);
+	LockNotPinnedObject(TypeRelationId, rightTypeId);
+	LockNotPinnedObject(TypeRelationId, operResultType);
+	LockNotPinnedObject(ProcedureRelationId, procedureId);
+	LockNotPinnedObject(ProcedureRelationId, restrictionId);
+	LockNotPinnedObject(ProcedureRelationId, joinId);
+
 	/* Add dependencies for the entry */
 	address = makeOperatorDependencies(tup, true, isUpdate);
 
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 528c17cd7f..9cceb6413b 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -593,6 +593,13 @@ ProcedureCreate(const char *procedureName,
 	if (is_update)
 		deleteDependencyRecordsFor(ProcedureRelationId, retval, true);
 
+	/*
+	 * CommandCounterIncrement here to ensure the new function entry is
+	 * visible when we'll check of object existence when recording the
+	 * dependencies.
+	 */
+	CommandCounterIncrement();
+
 	addrs = new_object_addresses();
 
 	ObjectAddressSet(myself, ProcedureRelationId, retval);
@@ -600,20 +607,24 @@ ProcedureCreate(const char *procedureName,
 	/* dependency on namespace */
 	ObjectAddressSet(referenced, NamespaceRelationId, procNamespace);
 	add_exact_object_address(&referenced, addrs);
+	LockNotPinnedObject(NamespaceRelationId, procNamespace);
 
 	/* dependency on implementation language */
 	ObjectAddressSet(referenced, LanguageRelationId, languageObjectId);
 	add_exact_object_address(&referenced, addrs);
+	LockNotPinnedObject(LanguageRelationId, languageObjectId);
 
 	/* dependency on return type */
 	ObjectAddressSet(referenced, TypeRelationId, returnType);
 	add_exact_object_address(&referenced, addrs);
+	LockNotPinnedObject(TypeRelationId, returnType);
 
 	/* dependency on transform used by return type, if any */
 	if ((trfid = get_transform_oid(returnType, languageObjectId, true)))
 	{
 		ObjectAddressSet(referenced, TransformRelationId, trfid);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(TransformRelationId, trfid);
 	}
 
 	/* dependency on parameter types */
@@ -621,12 +632,14 @@ ProcedureCreate(const char *procedureName,
 	{
 		ObjectAddressSet(referenced, TypeRelationId, allParams[i]);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(TypeRelationId, allParams[i]);
 
 		/* dependency on transform used by parameter type, if any */
 		if ((trfid = get_transform_oid(allParams[i], languageObjectId, true)))
 		{
 			ObjectAddressSet(referenced, TransformRelationId, trfid);
 			add_exact_object_address(&referenced, addrs);
+			LockNotPinnedObject(TransformRelationId, trfid);
 		}
 	}
 
@@ -635,6 +648,7 @@ ProcedureCreate(const char *procedureName,
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, prosupport);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, prosupport);
 	}
 
 	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
@@ -674,9 +688,6 @@ ProcedureCreate(const char *procedureName,
 		ArrayType  *set_items = NULL;
 		int			save_nestlevel = 0;
 
-		/* Advance command counter so new tuple can be seen by validator */
-		CommandCounterIncrement();
-
 		/*
 		 * Set per-function configuration parameters so that the validation is
 		 * done with the environment the function expects.  However, if
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 0602398a54..5e16c0fcef 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -438,10 +438,12 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri,
 
 	/* Add dependency on the publication */
 	ObjectAddressSet(referenced, PublicationRelationId, pubid);
+	LockNotPinnedObject(PublicationRelationId, pubid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 
 	/* Add dependency on the relation */
 	ObjectAddressSet(referenced, RelationRelationId, relid);
+	/* XXX Do we need a lock for RelationRelationId? */
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 
 	/* Add dependency on the objects mentioned in the qualifications */
@@ -454,6 +456,7 @@ publication_add_relation(Oid pubid, PublicationRelInfo *pri,
 	for (int i = 0; i < natts; i++)
 	{
 		ObjectAddressSubSet(referenced, RelationRelationId, relid, attarray[i]);
+		/* XXX Do we need a lock for RelationRelationId? */
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 	}
 
@@ -661,10 +664,12 @@ publication_add_schema(Oid pubid, Oid schemaid, bool if_not_exists)
 
 	/* Add dependency on the publication */
 	ObjectAddressSet(referenced, PublicationRelationId, pubid);
+	LockNotPinnedObject(PublicationRelationId, pubid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 
 	/* Add dependency on the schema */
 	ObjectAddressSet(referenced, NamespaceRelationId, schemaid);
+	LockNotPinnedObject(NamespaceRelationId, schemaid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 
 	/* Close the table */
diff --git a/src/backend/catalog/pg_range.c b/src/backend/catalog/pg_range.c
index 501a6ba410..e5b5a0b6f8 100644
--- a/src/backend/catalog/pg_range.c
+++ b/src/backend/catalog/pg_range.c
@@ -70,26 +70,31 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation,
 
 	ObjectAddressSet(referenced, TypeRelationId, rangeSubType);
 	add_exact_object_address(&referenced, addrs);
+	LockNotPinnedObject(TypeRelationId, rangeSubType);
 
 	ObjectAddressSet(referenced, OperatorClassRelationId, rangeSubOpclass);
 	add_exact_object_address(&referenced, addrs);
+	LockNotPinnedObject(OperatorClassRelationId, rangeSubOpclass);
 
 	if (OidIsValid(rangeCollation))
 	{
 		ObjectAddressSet(referenced, CollationRelationId, rangeCollation);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(CollationRelationId, rangeCollation);
 	}
 
 	if (OidIsValid(rangeCanonical))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, rangeCanonical);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, rangeCanonical);
 	}
 
 	if (OidIsValid(rangeSubDiff))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, rangeSubDiff);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, rangeSubDiff);
 	}
 
 	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
@@ -99,6 +104,7 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation,
 	referencing.classId = TypeRelationId;
 	referencing.objectId = multirangeTypeOid;
 	referencing.objectSubId = 0;
+	LockNotPinnedObject(TypeRelationId, rangeTypeOid);
 	recordDependencyOn(&referencing, &myself, DEPENDENCY_INTERNAL);
 
 	table_close(pg_range, RowExclusiveLock);
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 395dec8ed8..92614cdaaa 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -157,6 +157,12 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
 	 * Create dependencies.  We can/must skip this in bootstrap mode.
 	 */
 	if (!IsBootstrapProcessingMode())
+	{
+		/* Lock dependent objects */
+		LockNotPinnedObject(NamespaceRelationId, typeNamespace);
+		LockNotPinnedObject(ProcedureRelationId, F_SHELL_IN);
+		LockNotPinnedObject(ProcedureRelationId, F_SHELL_OUT);
+
 		GenerateTypeDependencies(tup,
 								 pg_type_desc,
 								 NULL,
@@ -166,6 +172,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
 								 false,
 								 true,	/* make extension dependency */
 								 false);
+	}
 
 	/* Post creation hook for new shell type */
 	InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
@@ -494,6 +501,31 @@ TypeCreate(Oid newTypeOid,
 	 * Create dependencies.  We can/must skip this in bootstrap mode.
 	 */
 	if (!IsBootstrapProcessingMode())
+	{
+		/*
+		 * CommandCounterIncrement here to ensure the new type  entry is
+		 * visible when we'll check of object existence when recording the
+		 * dependencies.
+		 */
+		CommandCounterIncrement();
+
+		/* Lock dependent objects */
+		LockNotPinnedObject(NamespaceRelationId, typeNamespace);
+		LockNotPinnedObject(ProcedureRelationId, inputProcedure);
+		LockNotPinnedObject(ProcedureRelationId, outputProcedure);
+		LockNotPinnedObject(ProcedureRelationId, receiveProcedure);
+		LockNotPinnedObject(ProcedureRelationId, sendProcedure);
+		LockNotPinnedObject(ProcedureRelationId, typmodinProcedure);
+		LockNotPinnedObject(ProcedureRelationId, typmodoutProcedure);
+		LockNotPinnedObject(ProcedureRelationId, analyzeProcedure);
+		LockNotPinnedObject(ProcedureRelationId, subscriptProcedure);
+		LockNotPinnedObject(TypeRelationId, baseType);
+		LockNotPinnedObject(CollationRelationId, typeCollation);
+		LockNotPinnedObject(TypeRelationId, elementType);
+		/* XXX Do we need a lock for RelationRelationId? */
+		if (relationKind == RELKIND_COMPOSITE_TYPE)
+			LockNotPinnedObject(TypeRelationId, typeObjectId);
+
 		GenerateTypeDependencies(tup,
 								 pg_type_desc,
 								 (defaultTypeBin ?
@@ -505,6 +537,7 @@ TypeCreate(Oid newTypeOid,
 								 isDependentType,
 								 true,	/* make extension dependency */
 								 rebuildDeps);
+	}
 
 	/* Post creation hook for new type */
 	InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 738bc46ae8..4a708030ac 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -367,6 +367,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 		toastobject.objectId = toast_relid;
 		toastobject.objectSubId = 0;
 
+		/* XXX Do we need a lock for RelationRelationId? */
 		recordDependencyOn(&toastobject, &baseobject, DEPENDENCY_INTERNAL);
 	}
 
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 4f99ebb447..57e86f576a 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -501,7 +501,10 @@ ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddre
 		currexts = getAutoExtensionsOfObject(address.classId,
 											 address.objectId);
 		if (!list_member_oid(currexts, refAddr.objectId))
+		{
+			LockNotPinnedObject(refAddr.classId, refAddr.objectId);
 			recordDependencyOn(&address, &refAddr, DEPENDENCY_AUTO_EXTENSION);
+		}
 	}
 
 	return address;
@@ -807,6 +810,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
 	pfree(replaces);
 
 	/* update dependency to point to the new schema */
+	LockNotPinnedObject(NamespaceRelationId, nspOid);
 	if (changeDependencyFor(classId, objid,
 							NamespaceRelationId, oldNspOid, nspOid) != 1)
 		elog(ERROR, "could not change schema dependency for object %u",
diff --git a/src/backend/commands/amcmds.c b/src/backend/commands/amcmds.c
index aaa0f9a1dc..8616a7c9fa 100644
--- a/src/backend/commands/amcmds.c
+++ b/src/backend/commands/amcmds.c
@@ -104,6 +104,7 @@ CreateAccessMethod(CreateAmStmt *stmt)
 	referenced.objectId = amhandler;
 	referenced.objectSubId = 0;
 
+	LockNotPinnedObject(ProcedureRelationId, amhandler);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	recordDependencyOnCurrentExtension(&myself, false);
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 78f96789b0..b54a04f4b0 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -1272,6 +1272,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 	 */
 	if (relam1 != relam2)
 	{
+		LockNotPinnedObject(AccessMethodRelationId, relam2);
 		if (changeDependencyFor(RelationRelationId,
 								r1,
 								AccessMethodRelationId,
@@ -1280,6 +1281,8 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 			elog(ERROR, "could not change access method dependency for relation \"%s.%s\"",
 				 get_namespace_name(get_rel_namespace(r1)),
 				 get_rel_name(r1));
+
+		LockNotPinnedObject(AccessMethodRelationId, relam1);
 		if (changeDependencyFor(RelationRelationId,
 								r2,
 								AccessMethodRelationId,
@@ -1381,6 +1384,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 			{
 				baseobject.objectId = r1;
 				toastobject.objectId = relform1->reltoastrelid;
+				/* XXX Do we need a lock for RelationRelationId? */
 				recordDependencyOn(&toastobject, &baseobject,
 								   DEPENDENCY_INTERNAL);
 			}
@@ -1389,6 +1393,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 			{
 				baseobject.objectId = r2;
 				toastobject.objectId = relform2->reltoastrelid;
+				/* XXX Do we need a lock for RelationRelationId? */
 				recordDependencyOn(&toastobject, &baseobject,
 								   DEPENDENCY_INTERNAL);
 			}
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 7a5ed6b985..8d0cdec59e 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -327,6 +327,7 @@ insert_event_trigger_tuple(const char *trigname, const char *eventname, Oid evtO
 	referenced.classId = ProcedureRelationId;
 	referenced.objectId = funcoid;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(ProcedureRelationId, funcoid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	/* Depend on extension, if any. */
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 1643c8c69a..669a5d6dd8 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1924,6 +1924,7 @@ InsertExtensionTuple(const char *extName, Oid extOwner,
 
 	ObjectAddressSet(nsp, NamespaceRelationId, schemaOid);
 	add_exact_object_address(&nsp, refobjs);
+	LockNotPinnedObject(NamespaceRelationId, schemaOid);
 
 	foreach(lc, requiredExtensions)
 	{
@@ -1932,6 +1933,7 @@ InsertExtensionTuple(const char *extName, Oid extOwner,
 
 		ObjectAddressSet(otherext, ExtensionRelationId, reqext);
 		add_exact_object_address(&otherext, refobjs);
+		LockNotPinnedObject(ExtensionRelationId, reqext);
 	}
 
 	/* Record all of them (this includes duplicate elimination) */
@@ -2968,6 +2970,7 @@ AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *o
 	table_close(extRel, RowExclusiveLock);
 
 	/* update dependency to point to the new schema */
+	LockNotPinnedObject(NamespaceRelationId, nspOid);
 	if (changeDependencyFor(ExtensionRelationId, extensionOid,
 							NamespaceRelationId, oldNspOid, nspOid) != 1)
 		elog(ERROR, "could not change schema dependency for extension %s",
@@ -3258,6 +3261,7 @@ ApplyExtensionUpdates(Oid extensionOid,
 			otherext.objectId = reqext;
 			otherext.objectSubId = 0;
 
+			LockNotPinnedObject(ExtensionRelationId, reqext);
 			recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
 		}
 
@@ -3414,6 +3418,7 @@ ExecAlterExtensionContentsRecurse(AlterExtensionContentsStmt *stmt,
 		/*
 		 * OK, add the dependency.
 		 */
+		LockNotPinnedObject(extension.classId, extension.objectId);
 		recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
 
 		/*
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index cf61bbac1f..735bca486c 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -642,6 +642,7 @@ CreateForeignDataWrapper(ParseState *pstate, CreateFdwStmt *stmt)
 		referenced.classId = ProcedureRelationId;
 		referenced.objectId = fdwhandler;
 		referenced.objectSubId = 0;
+		LockNotPinnedObject(ProcedureRelationId, fdwhandler);
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 	}
 
@@ -650,6 +651,7 @@ CreateForeignDataWrapper(ParseState *pstate, CreateFdwStmt *stmt)
 		referenced.classId = ProcedureRelationId;
 		referenced.objectId = fdwvalidator;
 		referenced.objectSubId = 0;
+		LockNotPinnedObject(ProcedureRelationId, fdwvalidator);
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 	}
 
@@ -811,6 +813,7 @@ AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt)
 			referenced.classId = ProcedureRelationId;
 			referenced.objectId = fdwhandler;
 			referenced.objectSubId = 0;
+			LockNotPinnedObject(ProcedureRelationId, fdwhandler);
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
 
@@ -819,6 +822,7 @@ AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt)
 			referenced.classId = ProcedureRelationId;
 			referenced.objectId = fdwvalidator;
 			referenced.objectSubId = 0;
+			LockNotPinnedObject(ProcedureRelationId, fdwvalidator);
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
 	}
@@ -951,6 +955,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
 	referenced.classId = ForeignDataWrapperRelationId;
 	referenced.objectId = fdw->fdwid;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(ForeignDataWrapperRelationId, fdw->fdwid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);
@@ -1195,6 +1200,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
 	referenced.classId = ForeignServerRelationId;
 	referenced.objectId = srv->serverid;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(ForeignServerRelationId, srv->serverid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	if (OidIsValid(useId))
@@ -1472,6 +1478,7 @@ CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid)
 	referenced.classId = ForeignServerRelationId;
 	referenced.objectId = server->serverid;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(ForeignServerRelationId, server->serverid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	table_close(ftrel, RowExclusiveLock);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 6593fd7d81..8207ef08b3 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1446,6 +1446,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
 		/* Add or replace dependency on support function */
 		if (OidIsValid(procForm->prosupport))
 		{
+			LockNotPinnedObject(ProcedureRelationId, newsupport);
 			if (changeDependencyFor(ProcedureRelationId, funcOid,
 									ProcedureRelationId, procForm->prosupport,
 									newsupport) != 1)
@@ -1459,6 +1460,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt)
 			referenced.classId = ProcedureRelationId;
 			referenced.objectId = newsupport;
 			referenced.objectSubId = 0;
+			LockNotPinnedObject(ProcedureRelationId, newsupport);
 			recordDependencyOn(&address, &referenced, DEPENDENCY_NORMAL);
 		}
 
@@ -1962,21 +1964,25 @@ CreateTransform(CreateTransformStmt *stmt)
 	/* dependency on language */
 	ObjectAddressSet(referenced, LanguageRelationId, langid);
 	add_exact_object_address(&referenced, addrs);
+	LockNotPinnedObject(LanguageRelationId, langid);
 
 	/* dependency on type */
 	ObjectAddressSet(referenced, TypeRelationId, typeid);
 	add_exact_object_address(&referenced, addrs);
+	LockNotPinnedObject(TypeRelationId, typeid);
 
 	/* dependencies on functions */
 	if (OidIsValid(fromsqlfuncid))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, fromsqlfuncid);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, fromsqlfuncid);
 	}
 	if (OidIsValid(tosqlfuncid))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, tosqlfuncid);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, tosqlfuncid);
 	}
 
 	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 309389e20d..b14eaad7a3 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -4377,8 +4377,10 @@ IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
 			ObjectAddressSet(parentIdx, RelationRelationId, parentOid);
 			ObjectAddressSet(partitionTbl, RelationRelationId,
 							 partitionIdx->rd_index->indrelid);
+			/* Do we lock for RelationRelationId?? */
 			recordDependencyOn(&partIdx, &parentIdx,
 							   DEPENDENCY_PARTITION_PRI);
+			/* Do we lock for RelationRelationId?? */
 			recordDependencyOn(&partIdx, &partitionTbl,
 							   DEPENDENCY_PARTITION_SEC);
 		}
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index b8b5c147c5..ca15106ca9 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -298,12 +298,14 @@ CreateOpFamily(CreateOpFamilyStmt *stmt, const char *opfname,
 	referenced.classId = AccessMethodRelationId;
 	referenced.objectId = amoid;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(AccessMethodRelationId, amoid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 
 	/* dependency on namespace */
 	referenced.classId = NamespaceRelationId;
 	referenced.objectId = namespaceoid;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(NamespaceRelationId, namespaceoid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	/* dependency on owner */
@@ -725,18 +727,21 @@ DefineOpClass(CreateOpClassStmt *stmt)
 	referenced.classId = NamespaceRelationId;
 	referenced.objectId = namespaceoid;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(NamespaceRelationId, namespaceoid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	/* dependency on opfamily */
 	referenced.classId = OperatorFamilyRelationId;
 	referenced.objectId = opfamilyoid;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(OperatorFamilyRelationId, opfamilyoid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 
 	/* dependency on indexed datatype */
 	referenced.classId = TypeRelationId;
 	referenced.objectId = typeoid;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(TypeRelationId, typeoid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	/* dependency on storage datatype */
@@ -745,6 +750,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
 		referenced.classId = TypeRelationId;
 		referenced.objectId = storageoid;
 		referenced.objectSubId = 0;
+		LockNotPinnedObject(TypeRelationId, storageoid);
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 	}
 
@@ -1486,6 +1492,13 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
 
 		heap_freetuple(tup);
 
+		/*
+		 * CommandCounterIncrement here to ensure the new operator entry is
+		 * visible when we'll check of object existence when recording the
+		 * dependencies.
+		 */
+		CommandCounterIncrement();
+
 		/* Make its dependencies */
 		myself.classId = AccessMethodOperatorRelationId;
 		myself.objectId = entryoid;
@@ -1496,6 +1509,7 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
 		referenced.objectSubId = 0;
 
 		/* see comments in amapi.h about dependency strength */
+		LockNotPinnedObject(OperatorRelationId, op->object);
 		recordDependencyOn(&myself, &referenced,
 						   op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
 
@@ -1504,6 +1518,7 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
 		referenced.objectId = op->refobjid;
 		referenced.objectSubId = 0;
 
+		LockNotPinnedObject(referenced.classId, op->refobjid);
 		recordDependencyOn(&myself, &referenced,
 						   op->ref_is_hard ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
 
@@ -1514,6 +1529,7 @@ storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
 			referenced.objectId = op->sortfamily;
 			referenced.objectSubId = 0;
 
+			LockNotPinnedObject(OperatorFamilyRelationId, op->sortfamily);
 			recordDependencyOn(&myself, &referenced,
 							   op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
 		}
@@ -1597,6 +1613,7 @@ storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
 		referenced.objectSubId = 0;
 
 		/* see comments in amapi.h about dependency strength */
+		LockNotPinnedObject(ProcedureRelationId, proc->object);
 		recordDependencyOn(&myself, &referenced,
 						   proc->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
 
@@ -1605,6 +1622,7 @@ storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
 		referenced.objectId = proc->refobjid;
 		referenced.objectSubId = 0;
 
+		LockNotPinnedObject(referenced.classId, proc->refobjid);
 		recordDependencyOn(&myself, &referenced,
 						   proc->ref_is_hard ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
 
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index 5872a3e192..58a69e7cc2 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -33,6 +33,7 @@
 
 #include "access/htup_details.h"
 #include "access/table.h"
+#include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/objectaccess.h"
 #include "catalog/pg_namespace.h"
@@ -656,11 +657,15 @@ AlterOperator(AlterOperatorStmt *stmt)
 	{
 		replaces[Anum_pg_operator_oprrest - 1] = true;
 		values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionOid);
+		if (OidIsValid(restrictionOid))
+			LockNotPinnedObject(ProcedureRelationId, restrictionOid);
 	}
 	if (updateJoin)
 	{
 		replaces[Anum_pg_operator_oprjoin - 1] = true;
 		values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
+		if (OidIsValid(joinOid))
+			LockNotPinnedObject(ProcedureRelationId, joinOid);
 	}
 	if (OidIsValid(commutatorOid))
 	{
@@ -688,6 +693,31 @@ AlterOperator(AlterOperatorStmt *stmt)
 
 	CatalogTupleUpdate(catalog, &tup->t_self, tup);
 
+
+	/* Lock dependent objects */
+	oprForm = (Form_pg_operator) GETSTRUCT(tup);
+
+	if (OidIsValid(oprForm->oprnamespace))
+		LockNotPinnedObject(NamespaceRelationId, oprForm->oprnamespace);
+
+	if (OidIsValid(oprForm->oprleft))
+		LockNotPinnedObject(TypeRelationId, oprForm->oprleft);
+
+	if (OidIsValid(oprForm->oprright))
+		LockNotPinnedObject(TypeRelationId, oprForm->oprright);
+
+	if (OidIsValid(oprForm->oprresult))
+		LockNotPinnedObject(TypeRelationId, oprForm->oprresult);
+
+	if (OidIsValid(oprForm->oprcode))
+		LockNotPinnedObject(ProcedureRelationId, oprForm->oprcode);
+
+	if (OidIsValid(oprForm->oprrest))
+		LockNotPinnedObject(ProcedureRelationId, oprForm->oprrest);
+
+	if (OidIsValid(oprForm->oprjoin))
+		LockNotPinnedObject(ProcedureRelationId, oprForm->oprjoin);
+
 	address = makeOperatorDependencies(tup, false, true);
 
 	if (OidIsValid(commutatorOid) || OidIsValid(negatorOid))
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 6ff3eba824..31e61e4e67 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -722,6 +722,7 @@ CreatePolicy(CreatePolicyStmt *stmt)
 	myself.objectId = policy_id;
 	myself.objectSubId = 0;
 
+	/* XXX Do we need a lock for RelationRelationId? */
 	recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
 
 	recordDependencyOnExpr(&myself, qual, qual_pstate->p_rtable,
@@ -1053,6 +1054,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
 	myself.objectId = policy_id;
 	myself.objectSubId = 0;
 
+	/* XXX Do we need a lock for RelationRelationId? */
 	recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
 
 	recordDependencyOnExpr(&myself, qual, qual_parse_rtable, DEPENDENCY_NORMAL);
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 881f90017e..fadfd9064f 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -190,12 +190,14 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 	/* dependency on the PL handler function */
 	ObjectAddressSet(referenced, ProcedureRelationId, handlerOid);
 	add_exact_object_address(&referenced, addrs);
+	LockNotPinnedObject(ProcedureRelationId, handlerOid);
 
 	/* dependency on the inline handler function, if any */
 	if (OidIsValid(inlineOid))
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, inlineOid);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, inlineOid);
 	}
 
 	/* dependency on the validator function, if any */
@@ -203,6 +205,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 	{
 		ObjectAddressSet(referenced, ProcedureRelationId, valOid);
 		add_exact_object_address(&referenced, addrs);
+		LockNotPinnedObject(ProcedureRelationId, valOid);
 	}
 
 	record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 28f8522264..b1db4e8933 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1681,6 +1681,7 @@ process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
 		depobject.classId = RelationRelationId;
 		depobject.objectId = RelationGetRelid(seqrel);
 		depobject.objectSubId = 0;
+		/* XXX Do we need a lock for RelationRelationId? */
 		recordDependencyOn(&depobject, &refobject, deptype);
 	}
 
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index 1db3ef69d2..372ae02650 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -536,6 +536,7 @@ CreateStatistics(CreateStatsStmt *stmt)
 	for (i = 0; i < nattnums; i++)
 	{
 		ObjectAddressSubSet(parentobject, RelationRelationId, relid, attnums[i]);
+		/* XXX Do we need a lock for RelationRelationId? */
 		recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO);
 	}
 
@@ -553,6 +554,7 @@ CreateStatistics(CreateStatsStmt *stmt)
 	if (!nattnums)
 	{
 		ObjectAddressSet(parentobject, RelationRelationId, relid);
+		/* XXX Do we need a lock for RelationRelationId? */
 		recordDependencyOn(&myself, &parentobject, DEPENDENCY_AUTO);
 	}
 
@@ -573,6 +575,7 @@ CreateStatistics(CreateStatsStmt *stmt)
 	 * than the underlying table(s).
 	 */
 	ObjectAddressSet(parentobject, NamespaceRelationId, namespaceId);
+	LockNotPinnedObject(NamespaceRelationId, namespaceId);
 	recordDependencyOn(&myself, &parentobject, DEPENDENCY_NORMAL);
 
 	recordDependencyOnOwner(StatisticExtRelationId, statoid, stxowner);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 66cda26a25..c66f110984 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3438,6 +3438,7 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
 	childobject.objectId = relationId;
 	childobject.objectSubId = 0;
 
+	/* XXX Do we need a lock for RelationRelationId? */
 	recordDependencyOn(&childobject, &parentobject,
 					   child_dependency_type(child_is_partition));
 
@@ -7349,7 +7350,9 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	/*
 	 * Add needed dependency entries for the new column.
 	 */
+	LockNotPinnedObject(TypeRelationId, attribute->atttypid);
 	add_column_datatype_dependency(myrelid, newattnum, attribute->atttypid);
+	LockNotPinnedObject(CollationRelationId, attribute->attcollation);
 	add_column_collation_dependency(myrelid, newattnum, attribute->attcollation);
 
 	/*
@@ -10174,6 +10177,7 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
 		ObjectAddress referenced;
 
 		ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
+		LockNotPinnedObject(ConstraintRelationId, parentConstr);
 		recordDependencyOn(&address, &referenced, DEPENDENCY_INTERNAL);
 	}
 
@@ -10465,8 +10469,10 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
 			 */
 			ObjectAddressSet(address, ConstraintRelationId, constrOid);
 			ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
+			LockNotPinnedObject(ConstraintRelationId, parentConstr);
 			recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
 			ObjectAddressSet(referenced, RelationRelationId, partitionId);
+			/* XXX Do we need a lock for RelationRelationId? */
 			recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
 
 			/* Make all this visible before recursing */
@@ -10967,9 +10973,11 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
 		/* Set up partition dependencies for the new constraint */
 		ObjectAddressSet(address, ConstraintRelationId, constrOid);
 		ObjectAddressSet(referenced, ConstraintRelationId, parentConstrOid);
+		LockDatabaseObject(ConstraintRelationId, parentConstrOid, 0, AccessShareLock);
 		recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
 		ObjectAddressSet(referenced, RelationRelationId,
 						 RelationGetRelid(partRel));
+		/* XXX Do we need a lock for RelationRelationId? */
 		recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
 
 		/* Done with the cloned constraint's tuple */
@@ -13254,7 +13262,9 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 	table_close(attrelation, RowExclusiveLock);
 
 	/* Install dependencies on new datatype and collation */
+	LockNotPinnedObject(TypeRelationId, targettype);
 	add_column_datatype_dependency(RelationGetRelid(rel), attnum, targettype);
+	LockNotPinnedObject(CollationRelationId, targetcollid);
 	add_column_collation_dependency(RelationGetRelid(rel), attnum, targetcollid);
 
 	/*
@@ -14816,6 +14826,7 @@ ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId)
 		 */
 		ObjectAddressSet(relobj, RelationRelationId, reloid);
 		ObjectAddressSet(referenced, AccessMethodRelationId, rd_rel->relam);
+		LockNotPinnedObject(AccessMethodRelationId, rd_rel->relam);
 		recordDependencyOn(&relobj, &referenced, DEPENDENCY_NORMAL);
 	}
 	else if (OidIsValid(oldAccessMethodId) &&
@@ -14835,6 +14846,7 @@ ATExecSetAccessMethodNoStorage(Relation rel, Oid newAccessMethodId)
 			   OidIsValid(rd_rel->relam));
 
 		/* Both are valid, so update the dependency */
+		LockNotPinnedObject(AccessMethodRelationId, rd_rel->relam);
 		changeDependencyFor(RelationRelationId, reloid,
 							AccessMethodRelationId,
 							oldAccessMethodId, rd_rel->relam);
@@ -16434,6 +16446,7 @@ ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
 	typeobj.classId = TypeRelationId;
 	typeobj.objectId = typeid;
 	typeobj.objectSubId = 0;
+	LockNotPinnedObject(TypeRelationId, typeid);
 	recordDependencyOn(&tableobj, &typeobj, DEPENDENCY_NORMAL);
 
 	/* Update pg_class.reloftype */
@@ -17192,14 +17205,17 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
 		CatalogTupleUpdate(classRel, &classTup->t_self, classTup);
 
 		/* Update dependency on schema if caller said so */
-		if (hasDependEntry &&
-			changeDependencyFor(RelationRelationId,
-								relOid,
-								NamespaceRelationId,
-								oldNspOid,
-								newNspOid) != 1)
-			elog(ERROR, "could not change schema dependency for relation \"%s\"",
-				 NameStr(classForm->relname));
+		if (hasDependEntry)
+		{
+			LockNotPinnedObject(NamespaceRelationId, newNspOid);
+			if (changeDependencyFor(RelationRelationId,
+									relOid,
+									NamespaceRelationId,
+									oldNspOid,
+									newNspOid) != 1)
+				elog(ERROR, "could not change schema dependency for relation \"%s\"",
+					 NameStr(classForm->relname));
+		}
 	}
 	if (!already_done)
 	{
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 95de402fa6..44b15349b3 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -1018,8 +1018,6 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 		((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
 
 		CatalogTupleUpdate(pgrel, &tuple->t_self, tuple);
-
-		CommandCounterIncrement();
 	}
 	else
 		CacheInvalidateRelcacheByTuple(tuple);
@@ -1027,6 +1025,12 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 	heap_freetuple(tuple);
 	table_close(pgrel, RowExclusiveLock);
 
+	/*
+	 * CommandCounterIncrement here to ensure the new trigger entry is visible
+	 * when we'll check of object existence when recording the dependencies.
+	 */
+	CommandCounterIncrement();
+
 	/*
 	 * If we're replacing a trigger, flush all the old dependencies before
 	 * recording new ones.
@@ -1045,6 +1049,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 	referenced.classId = ProcedureRelationId;
 	referenced.objectId = funcoid;
 	referenced.objectSubId = 0;
+	LockNotPinnedObject(ProcedureRelationId, funcoid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	if (isInternal && OidIsValid(constraintOid))
@@ -1058,6 +1063,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 		referenced.classId = ConstraintRelationId;
 		referenced.objectId = constraintOid;
 		referenced.objectSubId = 0;
+		LockNotPinnedObject(ConstraintRelationId, constraintOid);
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
 	}
 	else
@@ -1070,6 +1076,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 		referenced.classId = RelationRelationId;
 		referenced.objectId = RelationGetRelid(rel);
 		referenced.objectSubId = 0;
+		/* XXX Do we need a lock for RelationRelationId? */
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 
 		if (OidIsValid(constrrelid))
@@ -1077,6 +1084,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 			referenced.classId = RelationRelationId;
 			referenced.objectId = constrrelid;
 			referenced.objectSubId = 0;
+			/* XXX Do we need a lock for RelationRelationId? */
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 		}
 		/* Not possible to have an index dependency in this case */
@@ -1091,6 +1099,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 			referenced.classId = ConstraintRelationId;
 			referenced.objectId = constraintOid;
 			referenced.objectSubId = 0;
+			LockNotPinnedObject(TriggerRelationId, trigoid);
 			recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
 		}
 
@@ -1100,8 +1109,10 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 		if (OidIsValid(parentTriggerOid))
 		{
 			ObjectAddressSet(referenced, TriggerRelationId, parentTriggerOid);
+			LockNotPinnedObject(TriggerRelationId, parentTriggerOid);
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_PRI);
 			ObjectAddressSet(referenced, RelationRelationId, RelationGetRelid(rel));
+			/* XXX Do we need a lock for RelationRelationId? */
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
 		}
 	}
@@ -1116,6 +1127,7 @@ CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
 		for (i = 0; i < ncolumns; i++)
 		{
 			referenced.objectSubId = columns[i];
+			/* XXX Do we need a lock for RelationRelationId? */
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
 	}
@@ -1255,9 +1267,11 @@ TriggerSetParentTrigger(Relation trigRel,
 		ObjectAddressSet(depender, TriggerRelationId, childTrigId);
 
 		ObjectAddressSet(referenced, TriggerRelationId, parentTrigId);
+		LockNotPinnedObject(TriggerRelationId, parentTrigId);
 		recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_PRI);
 
 		ObjectAddressSet(referenced, RelationRelationId, childTableId);
+		/* XXX Do we need a lock for RelationRelationId? */
 		recordDependencyOn(&depender, &referenced, DEPENDENCY_PARTITION_SEC);
 	}
 	else
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index b7b5019f1e..29e02f4946 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -66,12 +66,12 @@ static DefElem *buildDefItem(const char *name, const char *val,
 /* --------------------- TS Parser commands ------------------------ */
 
 /*
- * lookup a parser support function and return its OID (as a Datum)
+ * lookup a parser support function and return its OID
  *
  * attnum is the pg_ts_parser column the function will go into
  */
-static Datum
-get_ts_parser_func(DefElem *defel, int attnum)
+static Oid
+get_ts_parser_func_oid(DefElem *defel, int attnum)
 {
 	List	   *funcName = defGetQualifiedName(defel);
 	Oid			typeId[3];
@@ -125,7 +125,7 @@ get_ts_parser_func(DefElem *defel, int attnum)
 						func_signature_string(funcName, nargs, NIL, typeId),
 						format_type_be(retTypeId))));
 
-	return ObjectIdGetDatum(procOid);
+	return procOid;
 }
 
 /*
@@ -214,6 +214,7 @@ DefineTSParser(List *names, List *parameters)
 	namestrcpy(&pname, prsname);
 	values[Anum_pg_ts_parser_prsname - 1] = NameGetDatum(&pname);
 	values[Anum_pg_ts_parser_prsnamespace - 1] = ObjectIdGetDatum(namespaceoid);
+	LockNotPinnedObject(NamespaceRelationId, namespaceoid);
 
 	/*
 	 * loop over the definition list and extract the information we need.
@@ -224,28 +225,38 @@ DefineTSParser(List *names, List *parameters)
 
 		if (strcmp(defel->defname, "start") == 0)
 		{
-			values[Anum_pg_ts_parser_prsstart - 1] =
-				get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
+			Oid			procoid = get_ts_parser_func_oid(defel, Anum_pg_ts_parser_prsstart);
+
+			values[Anum_pg_ts_parser_prsstart - 1] = ObjectIdGetDatum(procoid);
+			LockNotPinnedObject(ProcedureRelationId, procoid);
 		}
 		else if (strcmp(defel->defname, "gettoken") == 0)
 		{
-			values[Anum_pg_ts_parser_prstoken - 1] =
-				get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
+			Oid			procoid = get_ts_parser_func_oid(defel, Anum_pg_ts_parser_prstoken);
+
+			values[Anum_pg_ts_parser_prstoken - 1] = ObjectIdGetDatum(procoid);
+			LockNotPinnedObject(ProcedureRelationId, procoid);
 		}
 		else if (strcmp(defel->defname, "end") == 0)
 		{
-			values[Anum_pg_ts_parser_prsend - 1] =
-				get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
+			Oid			procoid = get_ts_parser_func_oid(defel, Anum_pg_ts_parser_prsend);
+
+			values[Anum_pg_ts_parser_prsend - 1] = ObjectIdGetDatum(procoid);
+			LockNotPinnedObject(ProcedureRelationId, procoid);
 		}
 		else if (strcmp(defel->defname, "headline") == 0)
 		{
-			values[Anum_pg_ts_parser_prsheadline - 1] =
-				get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
+			Oid			procoid = get_ts_parser_func_oid(defel, Anum_pg_ts_parser_prsheadline);
+
+			values[Anum_pg_ts_parser_prsheadline - 1] = ObjectIdGetDatum(procoid);
+			LockNotPinnedObject(ProcedureRelationId, procoid);
 		}
 		else if (strcmp(defel->defname, "lextypes") == 0)
 		{
-			values[Anum_pg_ts_parser_prslextype - 1] =
-				get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
+			Oid			procoid = get_ts_parser_func_oid(defel, Anum_pg_ts_parser_prslextype);
+
+			values[Anum_pg_ts_parser_prslextype - 1] = ObjectIdGetDatum(procoid);
+			LockNotPinnedObject(ProcedureRelationId, procoid);
 		}
 		else
 			ereport(ERROR,
@@ -474,6 +485,10 @@ DefineTSDictionary(List *names, List *parameters)
 
 	CatalogTupleInsert(dictRel, tup);
 
+	/* Lock objects */
+	LockNotPinnedObject(NamespaceRelationId, namespaceoid);
+	LockNotPinnedObject(TSTemplateRelationId, templId);
+
 	address = makeDictionaryDependencies(tup);
 
 	/* Post creation hook for new text search dictionary */
@@ -601,12 +616,12 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
 /* ---------------------- TS Template commands -----------------------*/
 
 /*
- * lookup a template support function and return its OID (as a Datum)
+ * lookup a template support function and return its OID
  *
  * attnum is the pg_ts_template column the function will go into
  */
-static Datum
-get_ts_template_func(DefElem *defel, int attnum)
+static Oid
+get_ts_template_func_oid(DefElem *defel, int attnum)
 {
 	List	   *funcName = defGetQualifiedName(defel);
 	Oid			typeId[4];
@@ -642,7 +657,7 @@ get_ts_template_func(DefElem *defel, int attnum)
 						func_signature_string(funcName, nargs, NIL, typeId),
 						format_type_be(retTypeId))));
 
-	return ObjectIdGetDatum(procOid);
+	return procOid;
 }
 
 /*
@@ -723,6 +738,7 @@ DefineTSTemplate(List *names, List *parameters)
 	namestrcpy(&dname, tmplname);
 	values[Anum_pg_ts_template_tmplname - 1] = NameGetDatum(&dname);
 	values[Anum_pg_ts_template_tmplnamespace - 1] = ObjectIdGetDatum(namespaceoid);
+	LockNotPinnedObject(NamespaceRelationId, namespaceoid);
 
 	/*
 	 * loop over the definition list and extract the information we need.
@@ -733,15 +749,19 @@ DefineTSTemplate(List *names, List *parameters)
 
 		if (strcmp(defel->defname, "init") == 0)
 		{
-			values[Anum_pg_ts_template_tmplinit - 1] =
-				get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
+			Oid			procoid = get_ts_template_func_oid(defel, Anum_pg_ts_template_tmplinit);
+
+			values[Anum_pg_ts_template_tmplinit - 1] = ObjectIdGetDatum(procoid);
 			nulls[Anum_pg_ts_template_tmplinit - 1] = false;
+			LockNotPinnedObject(ProcedureRelationId, procoid);
 		}
 		else if (strcmp(defel->defname, "lexize") == 0)
 		{
-			values[Anum_pg_ts_template_tmpllexize - 1] =
-				get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
+			Oid			procoid = get_ts_template_func_oid(defel, Anum_pg_ts_template_tmpllexize);
+
+			values[Anum_pg_ts_template_tmpllexize - 1] = ObjectIdGetDatum(procoid);
 			nulls[Anum_pg_ts_template_tmpllexize - 1] = false;
+			LockNotPinnedObject(ProcedureRelationId, procoid);
 		}
 		else
 			ereport(ERROR,
@@ -879,6 +899,7 @@ makeConfigurationDependencies(HeapTuple tuple, bool removeOld,
 			referenced.objectId = cfgmap->mapdict;
 			referenced.objectSubId = 0;
 			add_exact_object_address(&referenced, addrs);
+			LockNotPinnedObject(TSDictionaryRelationId, cfgmap->mapdict);
 		}
 
 		systable_endscan(scan);
@@ -998,6 +1019,10 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied)
 	values[Anum_pg_ts_config_cfgowner - 1] = ObjectIdGetDatum(GetUserId());
 	values[Anum_pg_ts_config_cfgparser - 1] = ObjectIdGetDatum(prsOid);
 
+	/* Lock objects */
+	LockNotPinnedObject(NamespaceRelationId, namespaceoid);
+	LockNotPinnedObject(TSParserRelationId, prsOid);
+
 	tup = heap_form_tuple(cfgRel->rd_att, values, nulls);
 
 	CatalogTupleInsert(cfgRel, tup);
@@ -1156,6 +1181,7 @@ ObjectAddress
 AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
 {
 	HeapTuple	tup;
+	Form_pg_ts_config cfg;
 	Oid			cfgId;
 	Relation	relMap;
 	ObjectAddress address;
@@ -1168,7 +1194,8 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
 				 errmsg("text search configuration \"%s\" does not exist",
 						NameListToString(stmt->cfgname))));
 
-	cfgId = ((Form_pg_ts_config) GETSTRUCT(tup))->oid;
+	cfg = (Form_pg_ts_config) GETSTRUCT(tup);
+	cfgId = cfg->oid;
 
 	/* must be owner */
 	if (!object_ownercheck(TSConfigRelationId, cfgId, GetUserId()))
@@ -1183,6 +1210,10 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
 	else if (stmt->tokentype)
 		DropConfigurationMapping(stmt, tup, relMap);
 
+	/* Lock dependent objects */
+	LockNotPinnedObject(NamespaceRelationId, cfg->cfgnamespace);
+	LockNotPinnedObject(TSParserRelationId, cfg->cfgparser);
+
 	/* Update dependencies */
 	makeConfigurationDependencies(tup, true, relMap);
 
@@ -1414,6 +1445,8 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
 				repl_val[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(dictNew);
 				repl_repl[Anum_pg_ts_config_map_mapdict - 1] = true;
 
+				LockNotPinnedObject(TSDictionaryRelationId, dictNew);
+
 				newtup = heap_modify_tuple(maptup,
 										   RelationGetDescr(relMap),
 										   repl_val, repl_null, repl_repl);
@@ -1456,6 +1489,8 @@ MakeConfigurationMapping(AlterTSConfigurationStmt *stmt,
 				slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapseqno - 1] = Int32GetDatum(j + 1);
 				slot[slotCount]->tts_values[Anum_pg_ts_config_map_mapdict - 1] = ObjectIdGetDatum(dictIds[j]);
 
+				LockNotPinnedObject(TSDictionaryRelationId, dictIds[j]);
+
 				ExecStoreVirtualTuple(slot[slotCount]);
 				slotCount++;
 
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 2a1e713335..9febaa24a7 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -1794,6 +1794,7 @@ makeRangeConstructors(const char *name, Oid namespace,
 		 * that they go away silently when the type is dropped.  Note that
 		 * pg_dump depends on this choice to avoid dumping the constructors.
 		 */
+		LockNotPinnedObject(TypeRelationId, rangeOid);
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
 	}
 }
@@ -1859,6 +1860,7 @@ makeMultirangeConstructors(const char *name, Oid namespace,
 	 * that they go away silently when the type is dropped.  Note that pg_dump
 	 * depends on this choice to avoid dumping the constructors.
 	 */
+	LockNotPinnedObject(TypeRelationId, multirangeOid);
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
 	pfree(argtypes);
 
@@ -2672,6 +2674,45 @@ AlterDomainDefault(List *names, Node *defaultRaw)
 
 	CatalogTupleUpdate(rel, &tup->t_self, newtuple);
 
+	/* Lock dependent objects */
+	typTup = (Form_pg_type) GETSTRUCT(newtuple);
+
+	if (OidIsValid(typTup->typnamespace))
+		LockNotPinnedObject(NamespaceRelationId, typTup->typnamespace);
+
+	if (OidIsValid(typTup->typinput))
+		LockNotPinnedObject(ProcedureRelationId, typTup->typinput);
+
+	if (OidIsValid(typTup->typoutput))
+		LockNotPinnedObject(ProcedureRelationId, typTup->typoutput);
+
+	if (OidIsValid(typTup->typreceive))
+		LockNotPinnedObject(ProcedureRelationId, typTup->typreceive);
+
+	if (OidIsValid(typTup->typsend))
+		LockNotPinnedObject(ProcedureRelationId, typTup->typsend);
+
+	if (OidIsValid(typTup->typmodin))
+		LockNotPinnedObject(ProcedureRelationId, typTup->typmodin);
+
+	if (OidIsValid(typTup->typmodout))
+		LockNotPinnedObject(ProcedureRelationId, typTup->typmodout);
+
+	if (OidIsValid(typTup->typanalyze))
+		LockNotPinnedObject(ProcedureRelationId, typTup->typanalyze);
+
+	if (OidIsValid(typTup->typsubscript))
+		LockNotPinnedObject(ProcedureRelationId, typTup->typsubscript);
+
+	if (OidIsValid(typTup->typbasetype))
+		LockNotPinnedObject(TypeRelationId, typTup->typbasetype);
+
+	if (OidIsValid(typTup->typcollation))
+		LockNotPinnedObject(CollationRelationId, typTup->typcollation);
+
+	if (OidIsValid(typTup->typelem))
+		LockNotPinnedObject(TypeRelationId, typTup->typelem);
+
 	/* Rebuild dependencies */
 	GenerateTypeDependencies(newtuple,
 							 rel,
@@ -4276,10 +4317,13 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
 	if (oldNspOid != nspOid &&
 		(isCompositeType || typform->typtype != TYPTYPE_COMPOSITE) &&
 		!isImplicitArray)
+	{
+		LockNotPinnedObject(NamespaceRelationId, nspOid);
 		if (changeDependencyFor(TypeRelationId, typeOid,
 								NamespaceRelationId, oldNspOid, nspOid) != 1)
 			elog(ERROR, "could not change schema dependency for type \"%s\"",
 				 format_type_be(typeOid));
+	}
 
 	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
 
@@ -4571,6 +4615,7 @@ AlterTypeRecurse(Oid typeOid, bool isImplicitArray,
 	SysScanDesc scan;
 	ScanKeyData key[1];
 	HeapTuple	domainTup;
+	Form_pg_type typeForm;
 
 	/* Since this function recurses, it could be driven to stack overflow */
 	check_stack_depth();
@@ -4619,6 +4664,45 @@ AlterTypeRecurse(Oid typeOid, bool isImplicitArray,
 	newtup = heap_modify_tuple(tup, RelationGetDescr(catalog),
 							   values, nulls, replaces);
 
+	/* Lock dependent objects */
+	typeForm = (Form_pg_type) GETSTRUCT(newtup);
+
+	if (OidIsValid(typeForm->typnamespace))
+		LockNotPinnedObject(NamespaceRelationId, typeForm->typnamespace);
+
+	if (OidIsValid(typeForm->typinput))
+		LockNotPinnedObject(ProcedureRelationId, typeForm->typinput);
+
+	if (OidIsValid(typeForm->typoutput))
+		LockNotPinnedObject(ProcedureRelationId, typeForm->typoutput);
+
+	if (OidIsValid(typeForm->typreceive))
+		LockNotPinnedObject(ProcedureRelationId, typeForm->typreceive);
+
+	if (OidIsValid(typeForm->typsend))
+		LockNotPinnedObject(ProcedureRelationId, typeForm->typsend);
+
+	if (OidIsValid(typeForm->typmodin))
+		LockNotPinnedObject(ProcedureRelationId, typeForm->typmodin);
+
+	if (OidIsValid(typeForm->typmodout))
+		LockNotPinnedObject(ProcedureRelationId, typeForm->typmodout);
+
+	if (OidIsValid(typeForm->typanalyze))
+		LockNotPinnedObject(ProcedureRelationId, typeForm->typanalyze);
+
+	if (OidIsValid(typeForm->typsubscript))
+		LockNotPinnedObject(ProcedureRelationId, typeForm->typsubscript);
+
+	if (OidIsValid(typeForm->typbasetype))
+		LockNotPinnedObject(TypeRelationId, typeForm->typbasetype);
+
+	if (OidIsValid(typeForm->typcollation))
+		LockNotPinnedObject(CollationRelationId, typeForm->typcollation);
+
+	if (OidIsValid(typeForm->typelem))
+		LockNotPinnedObject(TypeRelationId, typeForm->typelem);
+
 	CatalogTupleUpdate(catalog, &newtup->t_self, newtup);
 
 	/* Rebuild dependencies for this type */
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 6cc9a8d8bf..ccd03ceeb8 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -155,6 +155,7 @@ InsertRule(const char *rulname,
 	referenced.objectId = eventrel_oid;
 	referenced.objectSubId = 0;
 
+	/* XXX Do we need a lock for RelationRelationId? */
 	recordDependencyOn(&myself, &referenced,
 					   (evtype == CMD_SELECT) ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
 
diff --git a/src/backend/utils/errcodes.txt b/src/backend/utils/errcodes.txt
index 3250d539e1..60e8539fe3 100644
--- a/src/backend/utils/errcodes.txt
+++ b/src/backend/utils/errcodes.txt
@@ -271,6 +271,7 @@ Section: Class 28 - Invalid Authorization Specification
 Section: Class 2B - Dependent Privilege Descriptors Still Exist
 
 2B000    E    ERRCODE_DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST            dependent_privilege_descriptors_still_exist
+2BP02    E    ERRCODE_DEPENDENT_OBJECTS_DOES_NOT_EXIST                       dependent_objects_does_not_exist
 2BP01    E    ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST                          dependent_objects_still_exist
 
 Section: Class 2D - Invalid Transaction Termination
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index 7eee66f810..c57204cc40 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -101,6 +101,9 @@ typedef struct ObjectAddresses ObjectAddresses;
 /* in dependency.c */
 
 extern void AcquireDeletionLock(const ObjectAddress *object, int flags);
+extern void LockNotPinnedObjectById(const ObjectAddress *object);
+extern void LockNotPinnedObjectsById(const ObjectAddress *object, int nobject);
+extern void LockNotPinnedObject(Oid classid, Oid objid);
 
 extern void ReleaseDeletionLock(const ObjectAddress *object);
 
@@ -128,6 +131,9 @@ extern void add_exact_object_address(const ObjectAddress *object,
 extern bool object_address_present(const ObjectAddress *object,
 								   const ObjectAddresses *addrs);
 
+extern void lock_record_object_address_dependencies(const ObjectAddress *depender,
+													ObjectAddresses *referenced,
+													DependencyType behavior);
 extern void record_object_address_dependencies(const ObjectAddress *depender,
 											   ObjectAddresses *referenced,
 											   DependencyType behavior);
@@ -172,6 +178,7 @@ extern long changeDependenciesOf(Oid classId, Oid oldObjectId,
 extern long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
 								 Oid newRefObjectId);
 
+extern bool isObjectPinned(const ObjectAddress *object);
 extern Oid	getExtensionOfObject(Oid classId, Oid objectId);
 extern List *getAutoExtensionsOfObject(Oid classId, Oid objectId);
 
diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h
index 3a70d80e32..56f746264b 100644
--- a/src/include/catalog/objectaddress.h
+++ b/src/include/catalog/objectaddress.h
@@ -53,6 +53,7 @@ extern void check_object_ownership(Oid roleid,
 								   Node *object, Relation relation);
 
 extern Oid	get_object_namespace(const ObjectAddress *address);
+extern bool ObjectByIdExist(const ObjectAddress *address);
 
 extern bool is_objectclass_supported(Oid class_id);
 extern const char *get_object_class_descr(Oid class_id);
diff --git a/src/test/isolation/expected/test_dependencies_locks.out b/src/test/isolation/expected/test_dependencies_locks.out
new file mode 100644
index 0000000000..9b645d7aa5
--- /dev/null
+++ b/src/test/isolation/expected/test_dependencies_locks.out
@@ -0,0 +1,129 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1_begin s1_create_function_in_schema s2_drop_schema s1_commit
+step s1_begin: BEGIN;
+step s1_create_function_in_schema: CREATE FUNCTION testschema.foo() RETURNS int AS 'select 1' LANGUAGE sql;
+step s2_drop_schema: DROP SCHEMA testschema; <waiting ...>
+step s1_commit: COMMIT;
+step s2_drop_schema: <... completed>
+ERROR:  cannot drop schema testschema because other objects depend on it
+
+starting permutation: s2_begin s2_drop_schema s1_create_function_in_schema s2_commit
+step s2_begin: BEGIN;
+step s2_drop_schema: DROP SCHEMA testschema;
+step s1_create_function_in_schema: CREATE FUNCTION testschema.foo() RETURNS int AS 'select 1' LANGUAGE sql; <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_function_in_schema: <... completed>
+ERROR:  schema testschema does not exist
+
+starting permutation: s1_begin s1_alter_function_schema s2_drop_alterschema s1_commit
+step s1_begin: BEGIN;
+step s1_alter_function_schema: ALTER FUNCTION public.falter() SET SCHEMA alterschema;
+step s2_drop_alterschema: DROP SCHEMA alterschema; <waiting ...>
+step s1_commit: COMMIT;
+step s2_drop_alterschema: <... completed>
+ERROR:  cannot drop schema alterschema because other objects depend on it
+
+starting permutation: s2_begin s2_drop_alterschema s1_alter_function_schema s2_commit
+step s2_begin: BEGIN;
+step s2_drop_alterschema: DROP SCHEMA alterschema;
+step s1_alter_function_schema: ALTER FUNCTION public.falter() SET SCHEMA alterschema; <waiting ...>
+step s2_commit: COMMIT;
+step s1_alter_function_schema: <... completed>
+ERROR:  schema alterschema does not exist
+
+starting permutation: s1_begin s1_create_function_with_argtype s2_drop_foo_type s1_commit
+step s1_begin: BEGIN;
+step s1_create_function_with_argtype: CREATE FUNCTION fooargtype(num foo) RETURNS int AS 'select 1' LANGUAGE sql;
+step s2_drop_foo_type: DROP TYPE public.foo; <waiting ...>
+step s1_commit: COMMIT;
+step s2_drop_foo_type: <... completed>
+ERROR:  cannot drop type foo because other objects depend on it
+
+starting permutation: s2_begin s2_drop_foo_type s1_create_function_with_argtype s2_commit
+step s2_begin: BEGIN;
+step s2_drop_foo_type: DROP TYPE public.foo;
+step s1_create_function_with_argtype: CREATE FUNCTION fooargtype(num foo) RETURNS int AS 'select 1' LANGUAGE sql; <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_function_with_argtype: <... completed>
+ERROR:  type foo does not exist
+
+starting permutation: s1_begin s1_create_function_with_rettype s2_drop_foo_rettype s1_commit
+step s1_begin: BEGIN;
+step s1_create_function_with_rettype: CREATE FUNCTION footrettype() RETURNS id LANGUAGE sql RETURN 1;
+step s2_drop_foo_rettype: DROP DOMAIN id; <waiting ...>
+step s1_commit: COMMIT;
+step s2_drop_foo_rettype: <... completed>
+ERROR:  cannot drop type id because other objects depend on it
+
+starting permutation: s2_begin s2_drop_foo_rettype s1_create_function_with_rettype s2_commit
+step s2_begin: BEGIN;
+step s2_drop_foo_rettype: DROP DOMAIN id;
+step s1_create_function_with_rettype: CREATE FUNCTION footrettype() RETURNS id LANGUAGE sql RETURN 1; <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_function_with_rettype: <... completed>
+ERROR:  type id does not exist
+
+starting permutation: s1_begin s1_create_function_with_function s2_drop_function_f s1_commit
+step s1_begin: BEGIN;
+step s1_create_function_with_function: CREATE FUNCTION foofunc() RETURNS int LANGUAGE SQL RETURN f() + 1;
+step s2_drop_function_f: DROP FUNCTION f(); <waiting ...>
+step s1_commit: COMMIT;
+step s2_drop_function_f: <... completed>
+ERROR:  cannot drop function f() because other objects depend on it
+
+starting permutation: s2_begin s2_drop_function_f s1_create_function_with_function s2_commit
+step s2_begin: BEGIN;
+step s2_drop_function_f: DROP FUNCTION f();
+step s1_create_function_with_function: CREATE FUNCTION foofunc() RETURNS int LANGUAGE SQL RETURN f() + 1; <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_function_with_function: <... completed>
+ERROR:  function f() does not exist
+
+starting permutation: s1_begin s1_create_domain_with_domain s2_drop_domain_id s1_commit
+step s1_begin: BEGIN;
+step s1_create_domain_with_domain: CREATE DOMAIN idid as id;
+step s2_drop_domain_id: DROP DOMAIN id; <waiting ...>
+step s1_commit: COMMIT;
+step s2_drop_domain_id: <... completed>
+ERROR:  cannot drop type id because other objects depend on it
+
+starting permutation: s2_begin s2_drop_domain_id s1_create_domain_with_domain s2_commit
+step s2_begin: BEGIN;
+step s2_drop_domain_id: DROP DOMAIN id;
+step s1_create_domain_with_domain: CREATE DOMAIN idid as id; <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_domain_with_domain: <... completed>
+ERROR:  type id does not exist
+
+starting permutation: s1_begin s1_create_table_with_type s2_drop_footab_type s1_commit
+step s1_begin: BEGIN;
+step s1_create_table_with_type: CREATE TABLE tabtype(a footab);
+step s2_drop_footab_type: DROP TYPE public.footab; <waiting ...>
+step s1_commit: COMMIT;
+step s2_drop_footab_type: <... completed>
+ERROR:  cannot drop type footab because other objects depend on it
+
+starting permutation: s2_begin s2_drop_footab_type s1_create_table_with_type s2_commit
+step s2_begin: BEGIN;
+step s2_drop_footab_type: DROP TYPE public.footab;
+step s1_create_table_with_type: CREATE TABLE tabtype(a footab); <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_table_with_type: <... completed>
+ERROR:  type footab does not exist
+
+starting permutation: s1_begin s1_create_server_with_fdw_wrapper s2_drop_fdw_wrapper s1_commit
+step s1_begin: BEGIN;
+step s1_create_server_with_fdw_wrapper: CREATE SERVER srv_fdw_wrapper FOREIGN DATA WRAPPER fdw_wrapper;
+step s2_drop_fdw_wrapper: DROP FOREIGN DATA WRAPPER fdw_wrapper RESTRICT; <waiting ...>
+step s1_commit: COMMIT;
+step s2_drop_fdw_wrapper: <... completed>
+ERROR:  cannot drop foreign-data wrapper fdw_wrapper because other objects depend on it
+
+starting permutation: s2_begin s2_drop_fdw_wrapper s1_create_server_with_fdw_wrapper s2_commit
+step s2_begin: BEGIN;
+step s2_drop_fdw_wrapper: DROP FOREIGN DATA WRAPPER fdw_wrapper RESTRICT;
+step s1_create_server_with_fdw_wrapper: CREATE SERVER srv_fdw_wrapper FOREIGN DATA WRAPPER fdw_wrapper; <waiting ...>
+step s2_commit: COMMIT;
+step s1_create_server_with_fdw_wrapper: <... completed>
+ERROR:  foreign-data wrapper fdw_wrapper does not exist
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 0342eb39e4..1b67f0bffe 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -114,3 +114,4 @@ test: serializable-parallel-2
 test: serializable-parallel-3
 test: matview-write-skew
 test: lock-nowait
+test: test_dependencies_locks
diff --git a/src/test/isolation/specs/test_dependencies_locks.spec b/src/test/isolation/specs/test_dependencies_locks.spec
new file mode 100644
index 0000000000..5d04dfe9dc
--- /dev/null
+++ b/src/test/isolation/specs/test_dependencies_locks.spec
@@ -0,0 +1,89 @@
+setup
+{
+  CREATE SCHEMA testschema;
+  CREATE SCHEMA alterschema;
+  CREATE TYPE public.foo as enum ('one', 'two');
+  CREATE TYPE public.footab as enum ('three', 'four');
+  CREATE DOMAIN id AS int;
+  CREATE FUNCTION f() RETURNS int LANGUAGE SQL RETURN 1;
+  CREATE FUNCTION public.falter() RETURNS int LANGUAGE SQL RETURN 1;
+  CREATE FOREIGN DATA WRAPPER fdw_wrapper;
+}
+
+teardown
+{
+  DROP FUNCTION IF EXISTS testschema.foo();
+  DROP FUNCTION IF EXISTS fooargtype(num foo);
+  DROP FUNCTION IF EXISTS footrettype();
+  DROP FUNCTION IF EXISTS foofunc();
+  DROP FUNCTION IF EXISTS public.falter();
+  DROP FUNCTION IF EXISTS alterschema.falter();
+  DROP DOMAIN IF EXISTS idid;
+  DROP SERVER IF EXISTS srv_fdw_wrapper;
+  DROP TABLE IF EXISTS tabtype;
+  DROP SCHEMA IF EXISTS testschema;
+  DROP SCHEMA IF EXISTS alterschema;
+  DROP TYPE IF EXISTS public.foo;
+  DROP TYPE IF EXISTS public.footab;
+  DROP DOMAIN IF EXISTS id;
+  DROP FUNCTION IF EXISTS f();
+  DROP FOREIGN DATA WRAPPER IF EXISTS fdw_wrapper;
+}
+
+session "s1"
+
+step "s1_begin" { BEGIN; }
+step "s1_create_function_in_schema" { CREATE FUNCTION testschema.foo() RETURNS int AS 'select 1' LANGUAGE sql; }
+step "s1_create_function_with_argtype" { CREATE FUNCTION fooargtype(num foo) RETURNS int AS 'select 1' LANGUAGE sql; }
+step "s1_create_function_with_rettype" { CREATE FUNCTION footrettype() RETURNS id LANGUAGE sql RETURN 1; }
+step "s1_create_function_with_function" { CREATE FUNCTION foofunc() RETURNS int LANGUAGE SQL RETURN f() + 1; }
+step "s1_alter_function_schema" { ALTER FUNCTION public.falter() SET SCHEMA alterschema; }
+step "s1_create_domain_with_domain" { CREATE DOMAIN idid as id; }
+step "s1_create_table_with_type" { CREATE TABLE tabtype(a footab); }
+step "s1_create_server_with_fdw_wrapper" { CREATE SERVER srv_fdw_wrapper FOREIGN DATA WRAPPER fdw_wrapper; }
+step "s1_commit" { COMMIT; }
+
+session "s2"
+
+step "s2_begin" { BEGIN; }
+step "s2_drop_schema" { DROP SCHEMA testschema; }
+step "s2_drop_alterschema" { DROP SCHEMA alterschema; }
+step "s2_drop_foo_type" { DROP TYPE public.foo; }
+step "s2_drop_foo_rettype" { DROP DOMAIN id; }
+step "s2_drop_footab_type" { DROP TYPE public.footab; }
+step "s2_drop_function_f" { DROP FUNCTION f(); }
+step "s2_drop_domain_id" { DROP DOMAIN id; }
+step "s2_drop_fdw_wrapper" { DROP FOREIGN DATA WRAPPER fdw_wrapper RESTRICT; }
+step "s2_commit" { COMMIT; }
+
+# function - schema
+permutation "s1_begin" "s1_create_function_in_schema" "s2_drop_schema" "s1_commit"
+permutation "s2_begin" "s2_drop_schema" "s1_create_function_in_schema" "s2_commit"
+
+# alter function - schema
+permutation "s1_begin" "s1_alter_function_schema" "s2_drop_alterschema" "s1_commit"
+permutation "s2_begin" "s2_drop_alterschema" "s1_alter_function_schema" "s2_commit"
+
+# function - argtype
+permutation "s1_begin" "s1_create_function_with_argtype" "s2_drop_foo_type" "s1_commit"
+permutation "s2_begin" "s2_drop_foo_type" "s1_create_function_with_argtype" "s2_commit"
+
+# function - rettype
+permutation "s1_begin" "s1_create_function_with_rettype" "s2_drop_foo_rettype" "s1_commit"
+permutation "s2_begin" "s2_drop_foo_rettype" "s1_create_function_with_rettype" "s2_commit"
+
+# function - function
+permutation "s1_begin" "s1_create_function_with_function" "s2_drop_function_f" "s1_commit"
+permutation "s2_begin" "s2_drop_function_f" "s1_create_function_with_function" "s2_commit"
+
+# domain - domain
+permutation "s1_begin" "s1_create_domain_with_domain" "s2_drop_domain_id" "s1_commit"
+permutation "s2_begin" "s2_drop_domain_id" "s1_create_domain_with_domain" "s2_commit"
+
+# table - type
+permutation "s1_begin" "s1_create_table_with_type" "s2_drop_footab_type" "s1_commit"
+permutation "s2_begin" "s2_drop_footab_type" "s1_create_table_with_type" "s2_commit"
+
+# server - foreign data wrapper
+permutation "s1_begin" "s1_create_server_with_fdw_wrapper" "s2_drop_fdw_wrapper" "s1_commit"
+permutation "s2_begin" "s2_drop_fdw_wrapper" "s1_create_server_with_fdw_wrapper" "s2_commit"
-- 
2.34.1

