@@ -271,6 +271,7 @@ struct DropRelationCallbackState
271271{
272272 char relkind ;
273273 Oid heapOid ;
274+ Oid partParentOid ;
274275 bool concurrent ;
275276};
276277
@@ -1049,6 +1050,7 @@ RemoveRelations(DropStmt *drop)
10491050 /* Look up the appropriate relation using namespace search. */
10501051 state .relkind = relkind ;
10511052 state .heapOid = InvalidOid ;
1053+ state .partParentOid = InvalidOid ;
10521054 state .concurrent = drop -> concurrent ;
10531055 relOid = RangeVarGetRelidExtended (rel , lockmode , true,
10541056 false,
@@ -1078,6 +1080,8 @@ RemoveRelations(DropStmt *drop)
10781080/*
10791081 * Before acquiring a table lock, check whether we have sufficient rights.
10801082 * In the case of DROP INDEX, also try to lock the table before the index.
1083+ * Also, if the table to be dropped is a partition, we try to lock the parent
1084+ * first.
10811085 */
10821086static void
10831087RangeVarCallbackForDropRelation (const RangeVar * rel , Oid relOid , Oid oldRelOid ,
@@ -1087,6 +1091,7 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
10871091 struct DropRelationCallbackState * state ;
10881092 char relkind ;
10891093 char expected_relkind ;
1094+ bool is_partition ;
10901095 Form_pg_class classform ;
10911096 LOCKMODE heap_lockmode ;
10921097
@@ -1106,6 +1111,17 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
11061111 state -> heapOid = InvalidOid ;
11071112 }
11081113
1114+ /*
1115+ * Similarly, if we previously locked some other partition's heap, and
1116+ * the name we're looking up no longer refers to that relation, release
1117+ * the now-useless lock.
1118+ */
1119+ if (relOid != oldRelOid && OidIsValid (state -> partParentOid ))
1120+ {
1121+ UnlockRelationOid (state -> partParentOid , AccessExclusiveLock );
1122+ state -> partParentOid = InvalidOid ;
1123+ }
1124+
11091125 /* Didn't find a relation, so no need for locking or permission checks. */
11101126 if (!OidIsValid (relOid ))
11111127 return ;
@@ -1114,6 +1130,7 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
11141130 if (!HeapTupleIsValid (tuple ))
11151131 return ; /* concurrently dropped, so nothing to do */
11161132 classform = (Form_pg_class ) GETSTRUCT (tuple );
1133+ is_partition = classform -> relispartition ;
11171134
11181135 /*
11191136 * Both RELKIND_RELATION and RELKIND_PARTITIONED_TABLE are OBJECT_TABLE,
@@ -1157,6 +1174,19 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
11571174 if (OidIsValid (state -> heapOid ))
11581175 LockRelationOid (state -> heapOid , heap_lockmode );
11591176 }
1177+
1178+ /*
1179+ * Similarly, if the relation is a partition, we must acquire lock on its
1180+ * parent before locking the partition. That's because queries lock the
1181+ * parent before its partitions, so we risk deadlock it we do it the other
1182+ * way around.
1183+ */
1184+ if (is_partition && relOid != oldRelOid )
1185+ {
1186+ state -> partParentOid = get_partition_parent (relOid );
1187+ if (OidIsValid (state -> partParentOid ))
1188+ LockRelationOid (state -> partParentOid , AccessExclusiveLock );
1189+ }
11601190}
11611191
11621192/*
0 commit comments