@@ -1087,6 +1087,13 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
1087
1087
test = heap_lock_tuple (relation , & tuple , estate -> es_output_cid ,
1088
1088
lockmode , LockWaitBlock , false, & buffer ,
1089
1089
& hufd );
1090
+ /*
1091
+ * We must hold share lock on the buffer content while examining tuple
1092
+ * visibility. Afterwards, however, the tuples we have found to be
1093
+ * visible are guaranteed good as long as we hold the buffer pin.
1094
+ */
1095
+ LockBuffer (buffer , BUFFER_LOCK_SHARE );
1096
+
1090
1097
switch (test )
1091
1098
{
1092
1099
case HeapTupleMayBeUpdated :
@@ -1142,6 +1149,7 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
1142
1149
* loop here, as the new version of the row might not conflict
1143
1150
* anymore, or the conflicting tuple has actually been deleted.
1144
1151
*/
1152
+ LockBuffer (buffer , BUFFER_LOCK_UNLOCK );
1145
1153
ReleaseBuffer (buffer );
1146
1154
return false;
1147
1155
@@ -1175,6 +1183,8 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
1175
1183
/* Store target's existing tuple in the state's dedicated slot */
1176
1184
ExecStoreTuple (& tuple , mtstate -> mt_existing , buffer , false);
1177
1185
1186
+ LockBuffer (buffer , BUFFER_LOCK_UNLOCK );
1187
+
1178
1188
/*
1179
1189
* Make tuple and any needed join variables available to ExecQual and
1180
1190
* ExecProject. The EXCLUDED tuple is installed in ecxt_innertuple, while
0 commit comments