Don't rely on uninitialized value in MERGE / DELETE
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 15 Feb 2023 19:37:44 +0000 (20:37 +0100)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
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 <exclusion@gmail.com>
Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com>
Discussion: https://postgr.es/m/17792-0f89452029662c36@postgresql.org

src/backend/executor/nodeModifyTable.c

index 1ac65172e4446caa895d5225996fd3b5f942c630..f8e71ef1cc164de43904647e485130677a07d768 100644 (file)
@@ -2967,21 +2967,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;
 
                                        /*