Re: wrong results: merge when not matched by source

From: Tender Wang <tndrwang(at)gmail(dot)com>
To: Jeff Davis <pgsql(at)j-davis(dot)com>
Cc: pgsql-bugs(at)postgresql(dot)org, Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com>
Subject: Re: wrong results: merge when not matched by source
Date: 2026-09-18 02:02:42
Message-ID: CAHewXN=GhY6_McohLq5wV5GqqGVihCwnG6M3q42SUXTw5tqW1g@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

Jeff Davis <pgsql(at)j-davis(dot)com> 于2026年9月18日周五 03:18写道:
>
> -- Expected: only UPDATE of key=1; table is {(1, src)}.
> -- Actual: also INSERT of (NULL, NULL).

I think the problem is that the TM_Deleted case in
ExecMergeMatched() unconditionally sets *matched to false.

This is correct when the candidate row was originally a MATCHED row:
the source row still exists after the target row is concurrently
deleted, so it should be processed by the NOT MATCHED BY TARGET
actions.

However, it is not correct when processing an original NOT MATCHED BY
SOURCE row. In that case, the source row was already absent, and after
the concurrent deletion of the target row, there is no candidate row
left to process. Setting *matched to false causes ExecMerge() to
call ExecMergeNotMatched(), which executes the NOT MATCHED BY TARGET
INSERT using the null source side of the original join row.

A tentative fix is to set *matched to false only if the current
action is a MATCHED action, as in the attached patch.

There is another TM_Deleted case below, reached while handling
TM_Updated and following the update chain:
...
case TM_Deleted:
*matched = false;
goto out;
...

I think that case may need similar treatment. The existing
was_matched variable could perhaps be used there:
...
if (was_matched)
*matched = false;
...
I have left that case unchanged for now because I would like to
confirm whether the same state distinction applies to all paths
through that code.

The attached patch is intended to show the proposed fix and does not
yet include a regression test.

--
Thanks,
Tender Wang

Attachment Content-Type Size
0001-Fix-merge-issue.patch text/plain 1.4 KB

In response to

Responses

Browse pgsql-bugs by date

  From Date Subject
Next Message Tom Lane 2026-09-18 02:07:26 Re: BUG #19545: Integer truncation of `GinTuple.keylen` causes out-of-bounds read in parallel GIN index build
Previous Message Manuel Reyes Bravo 2026-09-17 22:40:44 Re: BUG #19692: Generic partition-pruning plan delays statement_timeout cancellation