Fix MERGE command tag for cross-partition updates.
authorDean Rasheed <dean.a.rasheed@gmail.com>
Wed, 22 Feb 2023 09:39:09 +0000 (09:39 +0000)
committerDean Rasheed <dean.a.rasheed@gmail.com>
Wed, 22 Feb 2023 09:39:09 +0000 (09:39 +0000)
This ensures that the row count in the command tag for a MERGE is
correctly computed. Previously, if MERGE updated a partitioned table,
the row count would be incorrect if any row was moved to a different
partition, since such updates were counted twice.

Back-patch to v15, where MERGE was introduced.

Discussion: https://postgr.es/m/CAEZATCWRMG7XX2QEsVL1LswmNo2d_YG8tKTLkpD3=Lp644S7rg@mail.gmail.com

src/backend/executor/nodeModifyTable.c
src/test/regress/expected/merge.out
src/test/regress/sql/merge.sql

index a94d7f86e5440f5a54c1588c720691338593694b..6f0543af83233a66f4df85163392ed1d33238e97 100644 (file)
@@ -2878,7 +2878,7 @@ lmerge_matched:
                }
                ExecUpdatePrepareSlot(resultRelInfo, newslot, context->estate);
                result = ExecUpdateAct(context, resultRelInfo, tupleid, NULL,
-                                      newslot, mtstate->canSetTag, &updateCxt);
+                                      newslot, false, &updateCxt);
                if (result == TM_Ok && updateCxt.updated)
                {
                    ExecUpdateEpilogue(context, &updateCxt, resultRelInfo,
index 2cf1409470b76a5bf31250e60741365efb8ded50..c298bfa314cf135bd1280994d1e212ed685e437d 100644 (file)
@@ -1582,6 +1582,10 @@ SELECT * FROM pa_target ORDER BY tid;
 ROLLBACK;
 -- try updating the partition key column
 BEGIN;
+CREATE FUNCTION merge_func() RETURNS integer LANGUAGE plpgsql AS $$
+DECLARE
+  result integer;
+BEGIN
 MERGE INTO pa_target t
   USING pa_source s
   ON t.tid = s.sid
@@ -1589,6 +1593,18 @@ MERGE INTO pa_target t
     UPDATE SET tid = tid + 1, balance = balance + delta, val = val || ' updated by merge'
   WHEN NOT MATCHED THEN
     INSERT VALUES (sid, delta, 'inserted by merge');
+IF FOUND THEN
+  GET DIAGNOSTICS result := ROW_COUNT;
+END IF;
+RETURN result;
+END;
+$$;
+SELECT merge_func();
+ merge_func 
+------------
+         14
+(1 row)
+
 SELECT * FROM pa_target ORDER BY tid;
  tid | balance |           val            
 -----+---------+--------------------------
index cef37e57d92aa18a93c97f35da7847bb09db4910..9ed648ad1f6e06b3650cff1dafca67a7be30de27 100644 (file)
@@ -999,6 +999,10 @@ ROLLBACK;
 
 -- try updating the partition key column
 BEGIN;
+CREATE FUNCTION merge_func() RETURNS integer LANGUAGE plpgsql AS $$
+DECLARE
+  result integer;
+BEGIN
 MERGE INTO pa_target t
   USING pa_source s
   ON t.tid = s.sid
@@ -1006,6 +1010,13 @@ MERGE INTO pa_target t
     UPDATE SET tid = tid + 1, balance = balance + delta, val = val || ' updated by merge'
   WHEN NOT MATCHED THEN
     INSERT VALUES (sid, delta, 'inserted by merge');
+IF FOUND THEN
+  GET DIAGNOSTICS result := ROW_COUNT;
+END IF;
+RETURN result;
+END;
+$$;
+SELECT merge_func();
 SELECT * FROM pa_target ORDER BY tid;
 ROLLBACK;