Don't rely on uninitialized value in MERGE / DELETE
authorAlvaro Herrera
Wed, 15 Feb 2023 19:37:44 +0000 (20:37 +0100)
committerAlvaro Herrera
Wed, 15 Feb 2023 19:37:44 +0000 (20:37 +0100)
On MERGE / WHEN MATCHED DELETE it's not possible to get cross-partition
updates, so we don't initialize cpUpdateRetrySlot; however, the code was
not careful to ignore the value in that case.  Make it do so.

Backpatch to 15.

Reported-by: Alexander Lakhin
Reviewed-by: Dean Rasheed
Discussion: https://postgr.es/m/17792-0f89452029662c36@postgresql.org

src/backend/executor/nodeModifyTable.c

index 30fe932aee0ad5bbe7853b3fbb6e09cb22935c03..508dcc4cbeaa10b3d413b6e65faf3e2af5808b2f 100644 (file)
@@ -2975,21 +2975,20 @@ lmerge_matched:;
                     */
 
                    /*
-                    * If cpUpdateRetrySlot is set, ExecCrossPartitionUpdate()
-                    * must have detected that the tuple was concurrently
-                    * updated, so we restart the search for an appropriate
-                    * WHEN MATCHED clause to process the updated tuple.
+                    * During an UPDATE, if cpUpdateRetrySlot is set, then
+                    * ExecCrossPartitionUpdate() must have detected that the
+                    * tuple was concurrently updated, so we restart the search
+                    * for an appropriate WHEN MATCHED clause to process the
+                    * updated tuple.
                     *
                     * In this case, ExecDelete() would already have performed
                     * EvalPlanQual() on the latest version of the tuple,
                     * which in turn would already have been loaded into
                     * ri_oldTupleSlot, so no need to do either of those
                     * things.
-                    *
-                    * XXX why do we not check the WHEN NOT MATCHED list in
-                    * this case?
                     */
-                   if (!TupIsNull(context->cpUpdateRetrySlot))
+                   if (commandType == CMD_UPDATE &&
+                       !TupIsNull(context->cpUpdateRetrySlot))
                        goto lmerge_matched;
 
                    /*