Lock acquisition in plancache.c should behave like CdbTryOpenRelation()
ExclusiveLock should be acquired in place of RowExclusiveLock for DMLs on user
tables.  If RowExclusiveLock is acquired, we may have a local deadlock on QD
when concurrent UPDATE statements are executed from within UDFs.
The problem is described in more detail here:
@@ -757,7 +757,20 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
* acquire a non-conflicting lock.
*/
if (list_member_int(plannedstmt->resultRelations, rt_index))
+ {
+ /*
+ * RowExclusiveLock is acquired in PostgreSQL here. Greenplum
+ * acquires ExclusiveLock to avoid distributed deadlock due to
+ * concurrent UPDATE/DELETE on the same table. This is in
+ * parity with CdbTryOpenRelation(). Catalog tables are
+ * replicated across cluster and don't suffer from the
+ * deadlock.
+ */
+ if (rte->relid > FirstNormalObjectId)
+ lockmode = ExclusiveLock;
+ else
lockmode = RowExclusiveLock;
+ }
else if (rowmark_member(plannedstmt->rowMarks, rt_index))
lockmode = RowShareLock;
else
@@ -817,7 +830,20 @@ ScanQueryForLocks(Query *parsetree, bool acquire)
case RTE_RELATION:
/* Acquire or release the appropriate type of lock */
if (rt_index == parsetree->resultRelation)
+ {
+ /*
+ * RowExclusiveLock is acquired in PostgreSQL here.
+ * Greenplum acquires ExclusiveLock to avoid distributed
+ * deadlock due to concurrent UPDATE/DELETE on the same
+ * table. This is in parity with CdbTryOpenRelation().
+ * Catalog tables are replicated across cluster and don't
+ * suffer from the deadlock.
+ */
+ if (rte->relid > FirstNormalObjectId)
+ lockmode = ExclusiveLock;
+ else
lockmode = RowExclusiveLock;
+ }
else if (rowmark_member(parsetree->rowMarks, rt_index))
lockmode = RowShareLock;
else
